feat: xlsx export of booking edit draft data for admins
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
"nelexa/zip": "^4.0",
|
"nelexa/zip": "^4.0",
|
||||||
"nesbot/carbon": "^3.8",
|
"nesbot/carbon": "^3.8",
|
||||||
"phpdocumentor/reflection-docblock": "^5.6",
|
"phpdocumentor/reflection-docblock": "^5.6",
|
||||||
|
"phpoffice/phpspreadsheet": "^5.4",
|
||||||
"phpstan/phpdoc-parser": "^2.0",
|
"phpstan/phpdoc-parser": "^2.0",
|
||||||
"spatie/crypto": "^2.1",
|
"spatie/crypto": "^2.1",
|
||||||
"symfony/apache-pack": "^1.0",
|
"symfony/apache-pack": "^1.0",
|
||||||
|
|||||||
Generated
+425
-80
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "a8cba38524e7e05db6de57adc2077b59",
|
"content-hash": "2249b13be37460c47093abb5ccde86a4",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "carbonphp/carbon-doctrine-types",
|
"name": "carbonphp/carbon-doctrine-types",
|
||||||
@@ -75,6 +75,85 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-12-11T17:09:12+00:00"
|
"time": "2023-12-11T17:09:12+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "composer/pcre",
|
||||||
|
"version": "3.3.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/composer/pcre.git",
|
||||||
|
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||||
|
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.4 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"phpstan/phpstan": "<1.11.10"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.12 || ^2",
|
||||||
|
"phpstan/phpstan-strict-rules": "^1 || ^2",
|
||||||
|
"phpunit/phpunit": "^8 || ^9"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"phpstan": {
|
||||||
|
"includes": [
|
||||||
|
"extension.neon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "3.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Composer\\Pcre\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jordi Boggiano",
|
||||||
|
"email": "[email protected]",
|
||||||
|
"homepage": "http://seld.be"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
|
||||||
|
"keywords": [
|
||||||
|
"PCRE",
|
||||||
|
"preg",
|
||||||
|
"regex",
|
||||||
|
"regular expression"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/composer/pcre/issues",
|
||||||
|
"source": "https://github.com/composer/pcre/tree/3.3.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://packagist.com",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/composer",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-11-12T16:29:46+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "defuse/php-encryption",
|
"name": "defuse/php-encryption",
|
||||||
"version": "v2.4.0",
|
"version": "v2.4.0",
|
||||||
@@ -2366,6 +2445,191 @@
|
|||||||
],
|
],
|
||||||
"time": "2025-12-07T16:03:21+00:00"
|
"time": "2025-12-07T16:03:21+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "maennchen/zipstream-php",
|
||||||
|
"version": "3.1.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/maennchen/ZipStream-PHP.git",
|
||||||
|
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/aeadcf5c412332eb426c0f9b4485f6accba2a99f",
|
||||||
|
"reference": "aeadcf5c412332eb426c0f9b4485f6accba2a99f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-zlib": "*",
|
||||||
|
"php-64bit": "^8.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"brianium/paratest": "^7.7",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.16",
|
||||||
|
"guzzlehttp/guzzle": "^7.5",
|
||||||
|
"mikey179/vfsstream": "^1.6",
|
||||||
|
"php-coveralls/php-coveralls": "^2.5",
|
||||||
|
"phpunit/phpunit": "^11.0",
|
||||||
|
"vimeo/psalm": "^6.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"guzzlehttp/psr7": "^2.4",
|
||||||
|
"psr/http-message": "^2.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"ZipStream\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Paul Duncan",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonatan Männchen",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jesse Donat",
|
||||||
|
"email": "[email protected]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "András Kolesár",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
|
||||||
|
"keywords": [
|
||||||
|
"stream",
|
||||||
|
"zip"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/maennchen/ZipStream-PHP/issues",
|
||||||
|
"source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.2"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/maennchen",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-01-27T12:07:53+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "markbaker/complex",
|
||||||
|
"version": "3.0.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MarkBaker/PHPComplex.git",
|
||||||
|
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
||||||
|
"reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Complex\\": "classes/src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Class for working with complex numbers",
|
||||||
|
"homepage": "https://github.com/MarkBaker/PHPComplex",
|
||||||
|
"keywords": [
|
||||||
|
"complex",
|
||||||
|
"mathematics"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MarkBaker/PHPComplex/issues",
|
||||||
|
"source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2"
|
||||||
|
},
|
||||||
|
"time": "2022-12-06T16:21:08+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "markbaker/matrix",
|
||||||
|
"version": "3.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MarkBaker/PHPMatrix.git",
|
||||||
|
"reference": "728434227fe21be27ff6d86621a1b13107a2562c"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c",
|
||||||
|
"reference": "728434227fe21be27ff6d86621a1b13107a2562c",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "dev-master",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpdocumentor/phpdocumentor": "2.*",
|
||||||
|
"phploc/phploc": "^4.0",
|
||||||
|
"phpmd/phpmd": "2.*",
|
||||||
|
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
||||||
|
"sebastian/phpcpd": "^4.0",
|
||||||
|
"squizlabs/php_codesniffer": "^3.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Matrix\\": "classes/src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"email": "[email protected]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Class for working with matrices",
|
||||||
|
"homepage": "https://github.com/MarkBaker/PHPMatrix",
|
||||||
|
"keywords": [
|
||||||
|
"mathematics",
|
||||||
|
"matrix",
|
||||||
|
"vector"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MarkBaker/PHPMatrix/issues",
|
||||||
|
"source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1"
|
||||||
|
},
|
||||||
|
"time": "2022-12-02T22:17:43+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "masterminds/html5",
|
"name": "masterminds/html5",
|
||||||
"version": "2.10.0",
|
"version": "2.10.0",
|
||||||
@@ -3086,6 +3350,115 @@
|
|||||||
},
|
},
|
||||||
"time": "2025-11-21T15:09:14+00:00"
|
"time": "2025-11-21T15:09:14+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "phpoffice/phpspreadsheet",
|
||||||
|
"version": "5.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
|
||||||
|
"reference": "48f2fe37d64c2dece0ef71fb2ac55497566782af"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/48f2fe37d64c2dece0ef71fb2ac55497566782af",
|
||||||
|
"reference": "48f2fe37d64c2dece0ef71fb2ac55497566782af",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer/pcre": "^1||^2||^3",
|
||||||
|
"ext-ctype": "*",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-fileinfo": "*",
|
||||||
|
"ext-filter": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"ext-xml": "*",
|
||||||
|
"ext-xmlreader": "*",
|
||||||
|
"ext-xmlwriter": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"ext-zlib": "*",
|
||||||
|
"maennchen/zipstream-php": "^2.1 || ^3.0",
|
||||||
|
"markbaker/complex": "^3.0",
|
||||||
|
"markbaker/matrix": "^3.0",
|
||||||
|
"php": "^8.1",
|
||||||
|
"psr/simple-cache": "^1.0 || ^2.0 || ^3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": "dev-main",
|
||||||
|
"dompdf/dompdf": "^2.0 || ^3.0",
|
||||||
|
"ext-intl": "*",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.2",
|
||||||
|
"mitoteam/jpgraph": "^10.5",
|
||||||
|
"mpdf/mpdf": "^8.1.1",
|
||||||
|
"phpcompatibility/php-compatibility": "^9.3",
|
||||||
|
"phpstan/phpstan": "^1.1 || ^2.0",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^1.0 || ^2.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0 || ^2.0",
|
||||||
|
"phpunit/phpunit": "^10.5",
|
||||||
|
"squizlabs/php_codesniffer": "^3.7",
|
||||||
|
"tecnickcom/tcpdf": "^6.5"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"dompdf/dompdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"ext-intl": "PHP Internationalization Functions, required for NumberFormat Wizard and StringHelper::setLocale()",
|
||||||
|
"mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
|
||||||
|
"mpdf/mpdf": "Option for rendering PDF with PDF Writer",
|
||||||
|
"tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Maarten Balliauw",
|
||||||
|
"homepage": "https://blog.maartenballiauw.be"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mark Baker",
|
||||||
|
"homepage": "https://markbakeruk.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Franck Lefevre",
|
||||||
|
"homepage": "https://rootslabs.net"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Erik Tilt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Adrien Crivelli"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Owen Leibman"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
|
||||||
|
"homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
|
||||||
|
"keywords": [
|
||||||
|
"OpenXML",
|
||||||
|
"excel",
|
||||||
|
"gnumeric",
|
||||||
|
"ods",
|
||||||
|
"php",
|
||||||
|
"spreadsheet",
|
||||||
|
"xls",
|
||||||
|
"xlsx"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
|
||||||
|
"source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/5.4.0"
|
||||||
|
},
|
||||||
|
"time": "2026-01-11T04:52:00+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "phpseclib/phpseclib",
|
"name": "phpseclib/phpseclib",
|
||||||
"version": "3.0.48",
|
"version": "3.0.48",
|
||||||
@@ -3770,6 +4143,57 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-09-11T13:17:53+00:00"
|
"time": "2024-09-11T13:17:53+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/simple-cache",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/simple-cache.git",
|
||||||
|
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865",
|
||||||
|
"reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\SimpleCache\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "https://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common interfaces for simple caching",
|
||||||
|
"keywords": [
|
||||||
|
"cache",
|
||||||
|
"caching",
|
||||||
|
"psr",
|
||||||
|
"psr-16",
|
||||||
|
"simple-cache"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/simple-cache/tree/3.0.0"
|
||||||
|
},
|
||||||
|
"time": "2021-10-29T13:26:27+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "spatie/crypto",
|
"name": "spatie/crypto",
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
@@ -10458,85 +10882,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2022-12-23T10:58:28+00:00"
|
"time": "2022-12-23T10:58:28+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "composer/pcre",
|
|
||||||
"version": "3.3.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/composer/pcre.git",
|
|
||||||
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
|
||||||
"reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7.4 || ^8.0"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"phpstan/phpstan": "<1.11.10"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpstan/phpstan": "^1.12 || ^2",
|
|
||||||
"phpstan/phpstan-strict-rules": "^1 || ^2",
|
|
||||||
"phpunit/phpunit": "^8 || ^9"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"phpstan": {
|
|
||||||
"includes": [
|
|
||||||
"extension.neon"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-main": "3.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Composer\\Pcre\\": "src"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Jordi Boggiano",
|
|
||||||
"email": "[email protected]",
|
|
||||||
"homepage": "http://seld.be"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
|
|
||||||
"keywords": [
|
|
||||||
"PCRE",
|
|
||||||
"preg",
|
|
||||||
"regex",
|
|
||||||
"regular expression"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/composer/pcre/issues",
|
|
||||||
"source": "https://github.com/composer/pcre/tree/3.3.2"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://packagist.com",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/composer",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2024-11-12T16:29:46+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "composer/semver",
|
"name": "composer/semver",
|
||||||
"version": "3.4.4",
|
"version": "3.4.4",
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20260113140000 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add date_id and hotel_id columns to booking_edit_draft table for export functionality';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE booking_edit_draft ADD date_id INT DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE booking_edit_draft ADD hotel_id INT DEFAULT NULL');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE booking_edit_draft DROP date_id');
|
||||||
|
$this->addSql('ALTER TABLE booking_edit_draft DROP hotel_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +1,32 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Controller\Admin;
|
namespace App\Controller\Admin;
|
||||||
|
|
||||||
use App\Admin\Field\JsonDataField;
|
use App\Admin\Field\JsonDataField;
|
||||||
use App\Entity\BookingEditDraft;
|
use App\Entity\BookingEditDraft;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
use App\Service\BookingExportService;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
use EasyCorp\Bundle\EasyAdminBundle\Config\Action;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
|
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Bundle\MakerBundle\Doctrine\RelationManyToOne;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
class BookingEditDraftCrudController extends AbstractCrudController
|
class BookingEditDraftCrudController extends AbstractCrudController
|
||||||
{
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly BookingExportService $exportService,
|
||||||
|
private readonly AdminUrlGenerator $adminUrlGenerator,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
public static function getEntityFqcn(): string
|
public static function getEntityFqcn(): string
|
||||||
{
|
{
|
||||||
return BookingEditDraft::class;
|
return BookingEditDraft::class;
|
||||||
@@ -26,14 +34,51 @@ class BookingEditDraftCrudController extends AbstractCrudController
|
|||||||
|
|
||||||
public function configureActions(Actions $actions): Actions
|
public function configureActions(Actions $actions): Actions
|
||||||
{
|
{
|
||||||
|
$exportAction = Action::new('exportExcel', 'Excel Export', 'fa fa-file-excel')
|
||||||
|
->linkToRoute(
|
||||||
|
'admin_booking_draft_export',
|
||||||
|
static fn (BookingEditDraft $entity): array => ['id' => $entity->getId()]
|
||||||
|
)
|
||||||
|
->displayIf(static fn (BookingEditDraft $entity): bool => $entity->hasExportData());
|
||||||
|
|
||||||
return $actions
|
return $actions
|
||||||
->add(Crud::PAGE_INDEX, Action::DETAIL)
|
->add(Crud::PAGE_INDEX, Action::DETAIL)
|
||||||
|
->add(Crud::PAGE_INDEX, $exportAction)
|
||||||
|
->add(Crud::PAGE_DETAIL, $exportAction)
|
||||||
->remove(Crud::PAGE_INDEX, Action::NEW)
|
->remove(Crud::PAGE_INDEX, Action::NEW)
|
||||||
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
->remove(Crud::PAGE_INDEX, Action::EDIT)
|
||||||
->remove(Crud::PAGE_DETAIL, Action::EDIT)
|
->remove(Crud::PAGE_DETAIL, Action::EDIT)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/admin/booking-draft/{id}/export', name: 'admin_booking_draft_export', requirements: ['id' => '\d+'])]
|
||||||
|
public function export(BookingEditDraft $draft): Response
|
||||||
|
{
|
||||||
|
if (false === $draft->hasExportData()) {
|
||||||
|
$this->addFlash('danger', 'Export nicht möglich: Reisedaten fehlen');
|
||||||
|
|
||||||
|
$url = $this->adminUrlGenerator
|
||||||
|
->setController(self::class)
|
||||||
|
->setAction(Action::INDEX)
|
||||||
|
->generateUrl();
|
||||||
|
|
||||||
|
return $this->redirect($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $this->exportService->createExportResponse($draft);
|
||||||
|
} catch (\RuntimeException $e) {
|
||||||
|
$this->addFlash('danger', 'Export fehlgeschlagen: ' . $e->getMessage());
|
||||||
|
|
||||||
|
$url = $this->adminUrlGenerator
|
||||||
|
->setController(self::class)
|
||||||
|
->setAction(Action::INDEX)
|
||||||
|
->generateUrl();
|
||||||
|
|
||||||
|
return $this->redirect($url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function configureCrud(Crud $crud): Crud
|
public function configureCrud(Crud $crud): Crud
|
||||||
{
|
{
|
||||||
return $crud
|
return $crud
|
||||||
|
|||||||
@@ -37,6 +37,18 @@ class BookingEditDraft
|
|||||||
#[ORM\Column(type: 'date_immutable')]
|
#[ORM\Column(type: 'date_immutable')]
|
||||||
private \DateTimeImmutable $travelDate;
|
private \DateTimeImmutable $travelDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BusProNet travel date ID (termin idbuspro) for loading travel data.
|
||||||
|
*/
|
||||||
|
#[ORM\Column(type: 'integer', nullable: true)]
|
||||||
|
private ?int $dateId = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BusProNet hotel ID for loading travel data.
|
||||||
|
*/
|
||||||
|
#[ORM\Column(type: 'integer', nullable: true)]
|
||||||
|
private ?int $hotelId = null;
|
||||||
|
|
||||||
#[ORM\Column(type: 'json')]
|
#[ORM\Column(type: 'json')]
|
||||||
private array $formData = [];
|
private array $formData = [];
|
||||||
|
|
||||||
@@ -95,6 +107,38 @@ class BookingEditDraft
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDateId(): ?int
|
||||||
|
{
|
||||||
|
return $this->dateId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDateId(?int $dateId): static
|
||||||
|
{
|
||||||
|
$this->dateId = $dateId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHotelId(): ?int
|
||||||
|
{
|
||||||
|
return $this->hotelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setHotelId(?int $hotelId): static
|
||||||
|
{
|
||||||
|
$this->hotelId = $hotelId;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the draft has the required travel IDs for export functionality.
|
||||||
|
*/
|
||||||
|
public function hasExportData(): bool
|
||||||
|
{
|
||||||
|
return null !== $this->dateId && null !== $this->hotelId;
|
||||||
|
}
|
||||||
|
|
||||||
public function getFormData(): array
|
public function getFormData(): array
|
||||||
{
|
{
|
||||||
return $this->formData;
|
return $this->formData;
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ class BookingEditDraftService
|
|||||||
$existingDraft = $this->findDraft($user, $bookingId);
|
$existingDraft = $this->findDraft($user, $bookingId);
|
||||||
|
|
||||||
$bookingNumber = $bookingDto->booking?->bookingNumber;
|
$bookingNumber = $bookingDto->booking?->bookingNumber;
|
||||||
|
$dateId = $bookingDto->travel->id;
|
||||||
|
$hotelId = $bookingDto->travel->hotelId;
|
||||||
|
|
||||||
if (null !== $existingDraft) {
|
if (null !== $existingDraft) {
|
||||||
$existingDraft->setFormData($formData);
|
$existingDraft->setFormData($formData);
|
||||||
@@ -70,9 +72,19 @@ class BookingEditDraftService
|
|||||||
if (null === $existingDraft->getBookingNumber() && null !== $bookingNumber) {
|
if (null === $existingDraft->getBookingNumber() && null !== $bookingNumber) {
|
||||||
$existingDraft->setBookingNumber($bookingNumber);
|
$existingDraft->setBookingNumber($bookingNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null === $existingDraft->getDateId() && null !== $dateId) {
|
||||||
|
$existingDraft->setDateId($dateId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $existingDraft->getHotelId() && null !== $hotelId) {
|
||||||
|
$existingDraft->setHotelId($hotelId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$draft = new BookingEditDraft($user, $bookingId, $travelDate, $formData);
|
$draft = new BookingEditDraft($user, $bookingId, $travelDate, $formData);
|
||||||
$draft->setBookingNumber($bookingNumber);
|
$draft->setBookingNumber($bookingNumber);
|
||||||
|
$draft->setDateId($dateId);
|
||||||
|
$draft->setHotelId($hotelId);
|
||||||
$this->entityManager->persist($draft);
|
$this->entityManager->persist($draft);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,353 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\BookingEditDraft;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates Excel exports from booking edit drafts.
|
||||||
|
*
|
||||||
|
* This service transforms draft booking data into a downloadable Excel file,
|
||||||
|
* converting all service, room, and pickup IDs to human-readable labels using
|
||||||
|
* travel data loaded from XML files.
|
||||||
|
*/
|
||||||
|
class BookingExportService
|
||||||
|
{
|
||||||
|
private const COLUMN_HEADERS = [
|
||||||
|
'Vorname',
|
||||||
|
'Nachname',
|
||||||
|
'Geburtsdatum',
|
||||||
|
'E-Mail',
|
||||||
|
'Mobil',
|
||||||
|
'Geschlecht',
|
||||||
|
'Nationalität',
|
||||||
|
'Straße',
|
||||||
|
'PLZ',
|
||||||
|
'Ort',
|
||||||
|
'Land',
|
||||||
|
'Größe',
|
||||||
|
'Gewicht',
|
||||||
|
'Schuhgröße',
|
||||||
|
'Zimmer',
|
||||||
|
'Zimmerwünsche',
|
||||||
|
'Kennzeichen',
|
||||||
|
'Skipass',
|
||||||
|
'Kurse',
|
||||||
|
'Verpflegung',
|
||||||
|
'Leihmaterial',
|
||||||
|
'Leihmaterial-Versicherung',
|
||||||
|
'Zusatzleistungen',
|
||||||
|
'Hinfahrt',
|
||||||
|
'Rückfahrt',
|
||||||
|
'Zustieg',
|
||||||
|
'Parkplatz',
|
||||||
|
'Versicherung',
|
||||||
|
'Sammelversicherung',
|
||||||
|
'Kaufgutschein',
|
||||||
|
'Aktionsgutschein',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly TravelDataService $travelDataService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a StreamedResponse with the Excel export for the given draft.
|
||||||
|
*
|
||||||
|
* @param BookingEditDraft $draft The draft to export
|
||||||
|
*
|
||||||
|
* @return StreamedResponse The response containing the Excel file
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException If travel data cannot be loaded
|
||||||
|
*/
|
||||||
|
public function createExportResponse(BookingEditDraft $draft): StreamedResponse
|
||||||
|
{
|
||||||
|
if (false === $draft->hasExportData()) {
|
||||||
|
throw new \RuntimeException('Draft is missing required travel IDs for export');
|
||||||
|
}
|
||||||
|
|
||||||
|
$travel = $this->travelDataService->getTravelData(
|
||||||
|
$draft->getDateId(),
|
||||||
|
$draft->getHotelId()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (null === $travel) {
|
||||||
|
throw new \RuntimeException('Could not load travel data for export');
|
||||||
|
}
|
||||||
|
|
||||||
|
$lookups = $this->buildLookups($travel);
|
||||||
|
$spreadsheet = $this->createSpreadsheet($draft, $lookups);
|
||||||
|
|
||||||
|
$filename = sprintf(
|
||||||
|
'buchung_%d_%s.xlsx',
|
||||||
|
$draft->getBookingNumber() ?? $draft->getBookingId(),
|
||||||
|
$draft->getTravelDate()->format('Y-m-d')
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = new StreamedResponse(function () use ($spreadsheet): void {
|
||||||
|
$writer = new Xlsx($spreadsheet);
|
||||||
|
$writer->save('php://output');
|
||||||
|
});
|
||||||
|
|
||||||
|
$response->headers->set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
|
||||||
|
$response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $filename));
|
||||||
|
$response->headers->set('Cache-Control', 'max-age=0');
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds lookup arrays for converting IDs to labels.
|
||||||
|
*
|
||||||
|
* @param \App\BusProNet\Model\Travel $travel The travel data
|
||||||
|
*
|
||||||
|
* @return array{services: array<int, string>, rooms: array<int, string>, pickups: array<int, string>}
|
||||||
|
*/
|
||||||
|
private function buildLookups(\App\BusProNet\Model\Travel $travel): array
|
||||||
|
{
|
||||||
|
$services = [];
|
||||||
|
$rooms = [];
|
||||||
|
$pickups = [];
|
||||||
|
|
||||||
|
foreach ($travel->additionalServices as $service) {
|
||||||
|
if (null !== $service->id && null !== $service->label) {
|
||||||
|
$services[$service->id] = $service->label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($travel->transportationServices as $service) {
|
||||||
|
if (null !== $service->id && null !== $service->label) {
|
||||||
|
$services[$service->id] = $service->label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($travel->rooms as $room) {
|
||||||
|
if (null !== $room->id && null !== $room->label) {
|
||||||
|
$rooms[$room->id] = $room->label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($travel->pickupsOutbound as $pickup) {
|
||||||
|
if (null !== $pickup->id) {
|
||||||
|
$pickups[$pickup->id] = $pickup->getLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($travel->pickupsInbound as $pickup) {
|
||||||
|
if (null !== $pickup->id) {
|
||||||
|
$pickups[$pickup->id] = $pickup->getLabel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'services' => $services,
|
||||||
|
'rooms' => $rooms,
|
||||||
|
'pickups' => $pickups,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the spreadsheet with participant data.
|
||||||
|
*
|
||||||
|
* @param BookingEditDraft $draft The draft containing form data
|
||||||
|
* @param array $lookups The ID to label lookup arrays
|
||||||
|
*/
|
||||||
|
private function createSpreadsheet(BookingEditDraft $draft, array $lookups): Spreadsheet
|
||||||
|
{
|
||||||
|
$spreadsheet = new Spreadsheet();
|
||||||
|
$sheet = $spreadsheet->getActiveSheet();
|
||||||
|
$sheet->setTitle('Teilnehmer');
|
||||||
|
|
||||||
|
// Write headers
|
||||||
|
foreach (self::COLUMN_HEADERS as $col => $header) {
|
||||||
|
$sheet->setCellValue([$col + 1, 1], $header);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Style header row
|
||||||
|
$headerStyle = [
|
||||||
|
'font' => ['bold' => true],
|
||||||
|
'fill' => [
|
||||||
|
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
|
||||||
|
'startColor' => ['rgb' => 'E0E0E0'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$lastColumn = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex(count(self::COLUMN_HEADERS));
|
||||||
|
$sheet->getStyle('A1:' . $lastColumn . '1')->applyFromArray($headerStyle);
|
||||||
|
|
||||||
|
// Write participant data
|
||||||
|
$formData = $draft->getFormData();
|
||||||
|
$participants = $formData['participants'] ?? [];
|
||||||
|
|
||||||
|
$row = 2;
|
||||||
|
foreach ($participants as $participant) {
|
||||||
|
$this->writeParticipantRow($sheet, $row, $participant, $lookups);
|
||||||
|
++$row;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-size columns
|
||||||
|
foreach (range(1, count(self::COLUMN_HEADERS)) as $col) {
|
||||||
|
$colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col);
|
||||||
|
$sheet->getColumnDimension($colLetter)->setAutoSize(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $spreadsheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a single participant row to the spreadsheet.
|
||||||
|
*/
|
||||||
|
private function writeParticipantRow(
|
||||||
|
\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet,
|
||||||
|
int $row,
|
||||||
|
array $participant,
|
||||||
|
array $lookups
|
||||||
|
): void {
|
||||||
|
$personal = $participant['personalData'] ?? [];
|
||||||
|
$address = $participant['address'] ?? [];
|
||||||
|
$body = $participant['bodyDimensions'] ?? [];
|
||||||
|
$room = $participant['roomAssignment'] ?? [];
|
||||||
|
$services = $participant['services'] ?? [];
|
||||||
|
$vouchers = $participant['vouchers'] ?? [];
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
$personal['firstName'] ?? '',
|
||||||
|
$personal['lastName'] ?? '',
|
||||||
|
$this->formatDate($personal['dateOfBirth'] ?? null),
|
||||||
|
$personal['email'] ?? '',
|
||||||
|
$personal['mobile'] ?? '',
|
||||||
|
$this->mapGender($personal['gender'] ?? null),
|
||||||
|
$personal['nationality'] ?? '',
|
||||||
|
$address['street'] ?? '',
|
||||||
|
$address['postCode'] ?? '',
|
||||||
|
$address['city'] ?? '',
|
||||||
|
$address['country'] ?? '',
|
||||||
|
$body['height'] ?? '',
|
||||||
|
$body['weight'] ?? '',
|
||||||
|
$body['shoeSize'] ?? '',
|
||||||
|
$this->resolveRoom($room['assignedRoomId'] ?? null, $lookups['rooms']),
|
||||||
|
$room['remarksRoom'] ?? '',
|
||||||
|
$participant['licensePlate'] ?? '',
|
||||||
|
$this->resolveService($services['skiPass'] ?? null, $lookups['services']),
|
||||||
|
$this->resolveServiceArray($services['courses'] ?? [], $lookups['services']),
|
||||||
|
$this->resolveServiceArray($services['board'] ?? [], $lookups['services']),
|
||||||
|
$this->resolveServiceArray($services['rentals'] ?? [], $lookups['services']),
|
||||||
|
$this->resolveService($services['rentalInsurance'] ?? null, $lookups['services']),
|
||||||
|
$this->resolveServiceArray($services['additionalServices'] ?? [], $lookups['services']),
|
||||||
|
$this->resolveService($services['transportationOutbound'] ?? null, $lookups['services']),
|
||||||
|
$this->resolveService($services['transportationInbound'] ?? null, $lookups['services']),
|
||||||
|
$this->resolvePickup($services['pickup'] ?? null, $lookups['pickups']),
|
||||||
|
$this->formatBoolean($services['parking'] ?? false),
|
||||||
|
$this->resolveService($services['insurance'] ?? null, $lookups['services']),
|
||||||
|
$this->formatBoolean($services['bulkInsuranceBooking'] ?? false),
|
||||||
|
$vouchers['purchaseVoucherCode'] ?? '',
|
||||||
|
$vouchers['promoVoucherCode'] ?? '',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($data as $col => $value) {
|
||||||
|
$sheet->setCellValue([$col + 1, $row], $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a date string to German format.
|
||||||
|
*/
|
||||||
|
private function formatDate(?string $date): string
|
||||||
|
{
|
||||||
|
if (null === $date || '' === $date) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$dateTime = new \DateTimeImmutable($date);
|
||||||
|
|
||||||
|
return $dateTime->format('d.m.Y');
|
||||||
|
} catch (\Exception) {
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps gender code to German label.
|
||||||
|
*/
|
||||||
|
private function mapGender(?string $gender): string
|
||||||
|
{
|
||||||
|
return match ($gender) {
|
||||||
|
'M' => 'männlich',
|
||||||
|
'W' => 'weiblich',
|
||||||
|
'D' => 'divers',
|
||||||
|
default => $gender ?? '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a boolean value to German text.
|
||||||
|
*/
|
||||||
|
private function formatBoolean(bool $value): string
|
||||||
|
{
|
||||||
|
return $value ? 'Ja' : 'Nein';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a single service ID to its label.
|
||||||
|
*/
|
||||||
|
private function resolveService(int|string|null $serviceId, array $lookup): string
|
||||||
|
{
|
||||||
|
if (null === $serviceId || '' === $serviceId) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = (int) $serviceId;
|
||||||
|
|
||||||
|
return $lookup[$id] ?? (string) $serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves an array of service IDs to labels, joined by pipe.
|
||||||
|
*/
|
||||||
|
private function resolveServiceArray(array $serviceIds, array $lookup): string
|
||||||
|
{
|
||||||
|
if (true === empty($serviceIds)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$labels = [];
|
||||||
|
foreach ($serviceIds as $serviceId) {
|
||||||
|
if (null !== $serviceId && '' !== $serviceId) {
|
||||||
|
$id = (int) $serviceId;
|
||||||
|
$labels[] = $lookup[$id] ?? (string) $serviceId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(', ', $labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a room ID to its label.
|
||||||
|
*/
|
||||||
|
private function resolveRoom(?int $roomId, array $lookup): string
|
||||||
|
{
|
||||||
|
if (null === $roomId) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lookup[$roomId] ?? (string) $roomId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a pickup ID to its label.
|
||||||
|
*/
|
||||||
|
private function resolvePickup(?int $pickupId, array $lookup): string
|
||||||
|
{
|
||||||
|
if (null === $pickupId) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lookup[$pickupId] ?? (string) $pickupId;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user