Automate pdf export with default tokens.
parent
e605729aaf
commit
87e4a5a4fd
|
@ -18,7 +18,8 @@
|
||||||
"guzzlehttp/guzzle": "^7.3",
|
"guzzlehttp/guzzle": "^7.3",
|
||||||
"php-di/php-di": "^6.3",
|
"php-di/php-di": "^6.3",
|
||||||
"symfony/yaml": "^5.2",
|
"symfony/yaml": "^5.2",
|
||||||
"mpdf/mpdf": "^8.0"
|
"mpdf/mpdf": "^8.0",
|
||||||
|
"swiftmailer/swiftmailer": "^6.2"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|
|
@ -4,8 +4,156 @@
|
||||||
"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": "e6f2abc31fc53724d858e127ce02978e",
|
"content-hash": "cbb7d7281f9622e5b410185c54558b28",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "doctrine/lexer",
|
||||||
|
"version": "1.2.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/lexer.git",
|
||||||
|
"reference": "e864bbf5904cb8f5bb334f99209b48018522f042"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/lexer/zipball/e864bbf5904cb8f5bb334f99209b48018522f042",
|
||||||
|
"reference": "e864bbf5904cb8f5bb334f99209b48018522f042",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^6.0",
|
||||||
|
"phpstan/phpstan": "^0.11.8",
|
||||||
|
"phpunit/phpunit": "^8.2"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/lexer.html",
|
||||||
|
"keywords": [
|
||||||
|
"annotations",
|
||||||
|
"docblock",
|
||||||
|
"lexer",
|
||||||
|
"parser",
|
||||||
|
"php"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/lexer/issues",
|
||||||
|
"source": "https://github.com/doctrine/lexer/tree/1.2.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/phpdoctrine",
|
||||||
|
"type": "patreon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2020-05-25T17:44:05+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "egulias/email-validator",
|
||||||
|
"version": "3.1.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/egulias/EmailValidator.git",
|
||||||
|
"reference": "c81f18a3efb941d8c4d2e025f6183b5c6d697307"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/egulias/EmailValidator/zipball/c81f18a3efb941d8c4d2e025f6183b5c6d697307",
|
||||||
|
"reference": "c81f18a3efb941d8c4d2e025f6183b5c6d697307",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/lexer": "^1.2",
|
||||||
|
"php": ">=7.2",
|
||||||
|
"symfony/polyfill-intl-idn": "^1.15"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"php-coveralls/php-coveralls": "^2.2",
|
||||||
|
"phpunit/phpunit": "^8.5.8|^9.3.3",
|
||||||
|
"vimeo/psalm": "^4"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Egulias\\EmailValidator\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Eduardo Gulias Davis"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library for validating emails against several RFCs",
|
||||||
|
"homepage": "https://github.com/egulias/EmailValidator",
|
||||||
|
"keywords": [
|
||||||
|
"email",
|
||||||
|
"emailvalidation",
|
||||||
|
"emailvalidator",
|
||||||
|
"validation",
|
||||||
|
"validator"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/egulias/EmailValidator/issues",
|
||||||
|
"source": "https://github.com/egulias/EmailValidator/tree/3.1.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/egulias",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2021-04-01T18:37:14+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/guzzle",
|
"name": "guzzlehttp/guzzle",
|
||||||
"version": "7.3.0",
|
"version": "7.3.0",
|
||||||
|
@ -864,6 +1012,81 @@
|
||||||
],
|
],
|
||||||
"time": "2021-02-11T11:37:01+00:00"
|
"time": "2021-02-11T11:37:01+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "swiftmailer/swiftmailer",
|
||||||
|
"version": "v6.2.7",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/swiftmailer/swiftmailer.git",
|
||||||
|
"reference": "15f7faf8508e04471f666633addacf54c0ab5933"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/15f7faf8508e04471f666633addacf54c0ab5933",
|
||||||
|
"reference": "15f7faf8508e04471f666633addacf54c0ab5933",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"egulias/email-validator": "^2.0|^3.1",
|
||||||
|
"php": ">=7.0.0",
|
||||||
|
"symfony/polyfill-iconv": "^1.0",
|
||||||
|
"symfony/polyfill-intl-idn": "^1.10",
|
||||||
|
"symfony/polyfill-mbstring": "^1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"mockery/mockery": "^1.0",
|
||||||
|
"symfony/phpunit-bridge": "^4.4|^5.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "Needed to support internationalized email addresses"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "6.2-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"lib/swift_required.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Chris Corbyn"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fabien Potencier",
|
||||||
|
"email": "fabien@symfony.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Swiftmailer, free feature-rich PHP mailer",
|
||||||
|
"homepage": "https://swiftmailer.symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"email",
|
||||||
|
"mail",
|
||||||
|
"mailer"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/swiftmailer/swiftmailer/issues",
|
||||||
|
"source": "https://github.com/swiftmailer/swiftmailer/tree/v6.2.7"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2021-03-09T12:30:35+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v5.2.6",
|
"version": "v5.2.6",
|
||||||
|
@ -1056,6 +1279,86 @@
|
||||||
],
|
],
|
||||||
"time": "2021-01-07T16:49:33+00:00"
|
"time": "2021-01-07T16:49:33+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-iconv",
|
||||||
|
"version": "v1.23.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-iconv.git",
|
||||||
|
"reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/63b5bb7db83e5673936d6e3b8b3e022ff6474933",
|
||||||
|
"reference": "63b5bb7db83e5673936d6e3b8b3e022ff6474933",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-iconv": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "1.23-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/polyfill",
|
||||||
|
"url": "https://github.com/symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Iconv\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for the Iconv extension",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"iconv",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-iconv/tree/v1.23.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2021-05-27T09:27:20+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-intl-grapheme",
|
"name": "symfony/polyfill-intl-grapheme",
|
||||||
"version": "v1.22.1",
|
"version": "v1.22.1",
|
||||||
|
@ -1120,6 +1423,93 @@
|
||||||
],
|
],
|
||||||
"time": "2021-01-22T09:19:47+00:00"
|
"time": "2021-01-22T09:19:47+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-intl-idn",
|
||||||
|
"version": "v1.23.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-intl-idn.git",
|
||||||
|
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/65bd267525e82759e7d8c4e8ceea44f398838e65",
|
||||||
|
"reference": "65bd267525e82759e7d8c4e8ceea44f398838e65",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1",
|
||||||
|
"symfony/polyfill-intl-normalizer": "^1.10",
|
||||||
|
"symfony/polyfill-php72": "^1.10"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-intl": "For best performance"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "1.23-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/polyfill",
|
||||||
|
"url": "https://github.com/symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Intl\\Idn\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Laurent Bassin",
|
||||||
|
"email": "laurent@bassin.info"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Trevor Rowbotham",
|
||||||
|
"email": "trevor.rowbotham@pm.me"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"idn",
|
||||||
|
"intl",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.23.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2021-05-27T09:27:20+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-intl-normalizer",
|
"name": "symfony/polyfill-intl-normalizer",
|
||||||
"version": "v1.22.1",
|
"version": "v1.22.1",
|
||||||
|
@ -1250,6 +1640,82 @@
|
||||||
],
|
],
|
||||||
"time": "2021-01-22T09:19:47+00:00"
|
"time": "2021-01-22T09:19:47+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "symfony/polyfill-php72",
|
||||||
|
"version": "v1.23.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/symfony/polyfill-php72.git",
|
||||||
|
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9a142215a36a3888e30d0a9eeea9766764e96976",
|
||||||
|
"reference": "9a142215a36a3888e30d0a9eeea9766764e96976",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.1"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "1.23-dev"
|
||||||
|
},
|
||||||
|
"thanks": {
|
||||||
|
"name": "symfony/polyfill",
|
||||||
|
"url": "https://github.com/symfony/polyfill"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Symfony\\Polyfill\\Php72\\": ""
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"bootstrap.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nicolas Grekas",
|
||||||
|
"email": "p@tchwork.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Symfony Community",
|
||||||
|
"homepage": "https://symfony.com/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
|
||||||
|
"homepage": "https://symfony.com",
|
||||||
|
"keywords": [
|
||||||
|
"compatibility",
|
||||||
|
"polyfill",
|
||||||
|
"portable",
|
||||||
|
"shim"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/symfony/polyfill-php72/tree/v1.23.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://symfony.com/sponsor",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/fabpot",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2021-05-27T09:17:38+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-php73",
|
"name": "symfony/polyfill-php73",
|
||||||
"version": "v1.22.1",
|
"version": "v1.22.1",
|
||||||
|
@ -3546,5 +4012,6 @@
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": [],
|
"platform": [],
|
||||||
"platform-dev": []
|
"platform-dev": [],
|
||||||
|
"plugin-api-version": "2.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,32 +3,50 @@
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 10pt;
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
.table {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.table table {
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0px auto;
|
||||||
|
float: none;
|
||||||
}
|
}
|
||||||
p { margin: 0pt; }
|
p { margin: 0pt; }
|
||||||
td { vertical-align: top; }
|
td { vertical-align: top; }
|
||||||
.items td {
|
table td {
|
||||||
border-left: 0.1mm solid #000000;
|
border-left: 0.1mm solid #000000;
|
||||||
border-right: 0.1mm solid #000000;
|
border-right: 0.1mm solid #000000;
|
||||||
}
|
}
|
||||||
table thead td { background-color: #EEEEEE;
|
table thead th {
|
||||||
|
background-color: #EEEEEE;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 0.1mm solid #000000;
|
border: 0.1mm solid #000000;
|
||||||
font-variant: small-caps;
|
|
||||||
}
|
}
|
||||||
.items td.blanktotal {
|
table tbody td {
|
||||||
background-color: #EEEEEE;
|
background-color: #FFF;
|
||||||
border: 0.1mm solid #000000;
|
border: 0.1mm solid #000000;
|
||||||
background-color: #FFFFFF;
|
padding-right: 2mm;
|
||||||
border: 0mm none #000000;
|
padding-left: 2mm;
|
||||||
border-top: 0.1mm solid #000000;
|
|
||||||
border-right: 0.1mm solid #000000;
|
|
||||||
}
|
}
|
||||||
.items td.totals {
|
tbody td.td-3,
|
||||||
|
tbody td.td-1 {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
border: 0.1mm solid #000000;
|
|
||||||
}
|
}
|
||||||
.items td.cost,
|
tbody tr.tr-2 td,
|
||||||
|
tbody tr.tr-3 td {
|
||||||
|
background-color: #EEE;
|
||||||
|
border-top: 0.4mm solid #000;
|
||||||
|
}
|
||||||
|
tbody tr.tr-3 td {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
tbody td.td-2,
|
||||||
.center {
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +62,7 @@
|
||||||
<p></p>
|
<p></p>
|
||||||
<p></p>
|
<p></p>
|
||||||
<p></p>
|
<p></p>
|
||||||
<p class="right">City, on 20. 9. 2021</p>
|
<p class="right">City, on [[today]]</p>
|
||||||
<p><strong>Honorarnote</br>Nummer [[number]]</strong></p>
|
<p><strong>Honorarnote</br>Nummer [[number]]</strong></p>
|
||||||
<p></p>
|
<p></p>
|
||||||
<p>Für meine Tätigkeit Programmieren von [[date_start]] bis [[date_end]] erlaube ich mir, folgenden Betrag in Rechnung zu stellen:</p>
|
<p>Für meine Tätigkeit Programmieren von [[date_start]] bis [[date_end]] erlaube ich mir, folgenden Betrag in Rechnung zu stellen:</p>
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# config/packages/translation.yaml
|
||||||
|
framework:
|
||||||
|
translator:
|
||||||
|
paths:
|
||||||
|
- '%kernel.project_dir%/translations'
|
||||||
|
|
|
@ -8,7 +8,7 @@ tracking_service:
|
||||||
report_id: '<89-123>'
|
report_id: '<89-123>'
|
||||||
export:
|
export:
|
||||||
template_path: '~/.config/rprt-cli/invoice-template.html'
|
template_path: '~/.config/rprt-cli/invoice-template.html'
|
||||||
output: '/tmp/YYYY-mm-invoice.pdf'
|
output: '/tmp/[[YEAR]]-[[month]]-invoice.pdf'
|
||||||
tokens:
|
tokens:
|
||||||
key: 'value to replace key'
|
key: 'value to replace key'
|
||||||
another_key: 'value to replace another key'
|
another_key: 'value to replace another key'
|
||||||
|
@ -17,13 +17,6 @@ export:
|
||||||
- 'Hours'
|
- 'Hours'
|
||||||
- 'Rate'
|
- 'Rate'
|
||||||
- 'Price'
|
- 'Price'
|
||||||
# reports:
|
|
||||||
# report short name:
|
|
||||||
# table:
|
|
||||||
# header:
|
|
||||||
# # overrides for table header
|
|
||||||
# hours: Quantity
|
|
||||||
# source: <youtrack-url>
|
|
||||||
projects:
|
projects:
|
||||||
'<short name of first project>':
|
'<short name of first project>':
|
||||||
name: '<Project long name>'
|
name: '<Project long name>'
|
||||||
|
@ -32,7 +25,6 @@ projects:
|
||||||
currency: 'EUR'
|
currency: 'EUR'
|
||||||
project column: 1
|
project column: 1
|
||||||
time column: 4
|
time column: 4
|
||||||
# time format m - minutes, h - hours
|
|
||||||
time format: 'm'
|
time format: 'm'
|
||||||
|
|
||||||
locale: 'en_GB'
|
locale: 'en_GB'
|
||||||
|
|
|
@ -55,6 +55,7 @@ class RprtCommand extends Command
|
||||||
$this->setName('rprt');
|
$this->setName('rprt');
|
||||||
$this->setDescription('Generate monthly report');
|
$this->setDescription('Generate monthly report');
|
||||||
// @TODO $this->addUsage('');
|
// @TODO $this->addUsage('');
|
||||||
|
// @TODO add sub options (config overrides)
|
||||||
$this->addOption(
|
$this->addOption(
|
||||||
'file',
|
'file',
|
||||||
'f',
|
'f',
|
||||||
|
@ -79,6 +80,18 @@ class RprtCommand extends Command
|
||||||
InputOption::VALUE_NONE,
|
InputOption::VALUE_NONE,
|
||||||
'Test login into youtrack service.'
|
'Test login into youtrack service.'
|
||||||
);
|
);
|
||||||
|
$this->addOption(
|
||||||
|
'output',
|
||||||
|
'o',
|
||||||
|
InputOption::VALUE_REQUIRED,
|
||||||
|
'Provide output file path. This option overrides configuration.'
|
||||||
|
);
|
||||||
|
$this->addOption(
|
||||||
|
'send',
|
||||||
|
's',
|
||||||
|
InputOption::VALUE_NONE,
|
||||||
|
'Send pdf export via email to recipient.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output) : int
|
protected function execute(InputInterface $input, OutputInterface $output) : int
|
||||||
|
@ -101,13 +114,19 @@ class RprtCommand extends Command
|
||||||
if ($pdf = $input->getOption('pdf')) {
|
if ($pdf = $input->getOption('pdf')) {
|
||||||
$nice_data = $this->csv->arangeDataForPdfExport($data);
|
$nice_data = $this->csv->arangeDataForPdfExport($data);
|
||||||
// @TODO method gatherTokens();
|
// @TODO method gatherTokens();
|
||||||
$this->pdfExport->fromDataToPdf($nice_data);
|
if ($output = $input->getOption('output')) {
|
||||||
|
$this->pdfExport->setOutput($output);
|
||||||
|
}
|
||||||
|
$output_path = $this->pdfExport->fromDataToPdf($nice_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Command::SUCCESS;
|
// return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
if ($send = $input->getOption('send') && $output_path) {
|
||||||
|
// Send email to configured address.
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->dummyOutput($input, $output);
|
// $this->dummyOutput($input, $output);
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,9 +95,9 @@ class CsvReport implements CsvReportInterface
|
||||||
$price = $hours * (int) $config['price'];
|
$price = $hours * (int) $config['price'];
|
||||||
$row = [
|
$row = [
|
||||||
$config['name'],
|
$config['name'],
|
||||||
$hours,
|
number_format($hours, 2, ',', '.'),
|
||||||
$config['price'],
|
number_format($config['price'], 2, ',', '.'),
|
||||||
$hours * $config['price'],
|
number_format($price, 2, ',', '.'),
|
||||||
];
|
];
|
||||||
$rows[] = $row;
|
$rows[] = $row;
|
||||||
$totalHours += $hours;
|
$totalHours += $hours;
|
||||||
|
@ -105,7 +105,8 @@ class CsvReport implements CsvReportInterface
|
||||||
}
|
}
|
||||||
// @TODO Check rate in final result.
|
// @TODO Check rate in final result.
|
||||||
// $rows[] = [$this->translator->trans('Sum'), $totalHours, $config['price'], $totalPrice];
|
// $rows[] = [$this->translator->trans('Sum'), $totalHours, $config['price'], $totalPrice];
|
||||||
$rows[] = ['Sum', $totalHours, $config['price'], $totalPrice];
|
$rows[] = ['Gesamt netto', number_format($totalHours, 2, ',', '.'), number_format($config['price'], 2, ',', '.'), number_format($totalPrice, 2, ',', '.')];
|
||||||
|
$rows[] = [null, null, 'Gessamt brutto', number_format($totalPrice, 2, ',', '.')];
|
||||||
|
|
||||||
return $rows;
|
return $rows;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ class PdfExportService implements PdfExportInterface {
|
||||||
public function getTemplatePath(): ?string
|
public function getTemplatePath(): ?string
|
||||||
{
|
{
|
||||||
if (!isset($this->templatePath)) {
|
if (!isset($this->templatePath)) {
|
||||||
$template_path = $this->config->get('report.template_path', FALSE);
|
$template_path = $this->config->get('export.template_path', FALSE);
|
||||||
if (!$template_path) {
|
if (!$template_path) {
|
||||||
$template_path = readline('Enter template file path: ');
|
$template_path = readline('Enter template file path: ');
|
||||||
}
|
}
|
||||||
|
@ -45,19 +45,33 @@ class PdfExportService implements PdfExportInterface {
|
||||||
throw new Exception('Template file not found!');
|
throw new Exception('Template file not found!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO move this method to CsvReport.
|
||||||
|
// Add classes to table elements.
|
||||||
|
// @TODO would it make sense to allow more per user extending?
|
||||||
public function parsedDataToHtmlTable(array $data): ?string {
|
public function parsedDataToHtmlTable(array $data): ?string {
|
||||||
$table = '<table><thead><tr>';
|
$table = '<table><thead><tr class="tr-header">';
|
||||||
$header = array_shift($data);
|
$header = array_shift($data);
|
||||||
foreach ($header as $cell) {
|
foreach ($header as $index => $cell) {
|
||||||
$table .= "<th>{$cell}</th>";
|
$table .= "<th class=\"th-{$index}\">{$cell}</th>";
|
||||||
}
|
}
|
||||||
$table .= '</tr></thead><tbody>';
|
$table .= '</tr></thead><tbody>';
|
||||||
foreach ($data as $row) {
|
foreach ($data as $row_index => $row) {
|
||||||
$cells = [];
|
list($cells, $colspan) = [[], 0];
|
||||||
foreach ($row as $cell) {
|
foreach ($row as $index => $cell) {
|
||||||
$cells[] = "<td>{$cell}</td>";
|
if (!$cell) {
|
||||||
|
$colspan += 1;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
$rows[] = '<tr>' . implode($cells) . '</tr>';
|
if ($colspan) {
|
||||||
|
$colspan += 1;
|
||||||
|
$cells[] = "<td class=\"td-{$index}\" colspan=\"{$colspan}\">{$cell}</td>";
|
||||||
|
$colspan = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$cells[] = "<td class=\"td-{$index}\">{$cell}</td>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rows[] = "<tr class=\"tr-{$row_index}\">" . implode($cells) . '</tr>';
|
||||||
}
|
}
|
||||||
$table .= implode('', $rows);
|
$table .= implode('', $rows);
|
||||||
$table .= '</tbody></table>';
|
$table .= '</tbody></table>';
|
||||||
|
@ -73,31 +87,95 @@ class PdfExportService implements PdfExportInterface {
|
||||||
return $template;
|
return $template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @TODO write a method to gather tokens.
|
||||||
|
public function getTokensInTemplate(string $template): array {
|
||||||
|
// @TODO find substrings of type [[key]]
|
||||||
|
preg_match_all('/\[\[([a-z0-9-_]+)\]\]/', $template, $match);
|
||||||
|
return $match[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO support multiple templates by adding template id in config.
|
||||||
|
/**
|
||||||
|
* Get tokens to replace in the template.
|
||||||
|
*
|
||||||
|
* @param string $template_path
|
||||||
|
* Path to the template file (long term plan is to support multiple templates).
|
||||||
|
* @param bool $skip_missing
|
||||||
|
* Just skip missing tokens.
|
||||||
|
* @param array $runtime_tokens
|
||||||
|
* Provide tokens at runtime of the application (not supported yet). @TODO
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Token keys and values array.
|
||||||
|
*/
|
||||||
|
public function gatherTokensForTemplate(string $template_path, bool $skip_missing = FALSE, array $runtime_tokens = []): array {
|
||||||
|
list($tokens, $missing) = [[], []];
|
||||||
|
$token_keys = $this->getTokensInTemplate(file_get_contents($template_path));
|
||||||
|
$config_tokens = $this->config->get('export.tokens');
|
||||||
|
foreach ($token_keys as $token_key) {
|
||||||
|
if (isset($runtime_tokens[$token_key])) {
|
||||||
|
$tokens[$token_key] = $runtime_tokens[$token_key];
|
||||||
|
}
|
||||||
|
elseif (!isset($config_tokens[$token_key]) && !$skip_missing) {
|
||||||
|
$tokens[$token_key] = readline("Enter value to replace [[{$token_key}]] in template: ");
|
||||||
|
}
|
||||||
|
elseif (isset($config_tokens[$token_key])) {
|
||||||
|
$tokens[$token_key] = $config_tokens[$token_key];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$missing[] = $token_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $tokens;
|
||||||
|
}
|
||||||
|
|
||||||
public function pdfExport(string $html, $output = null): bool {
|
public function pdfExport(string $html, $output = null): bool {
|
||||||
$this->mpdf->SetProtection(array('print'));
|
$this->mpdf->SetProtection(array('print'));
|
||||||
$this->mpdf->SetTitle("Acme Trading Co. - Invoice");
|
// @TODO make configurable.
|
||||||
$this->mpdf->SetAuthor("Acme Trading Co.");
|
$this->mpdf->SetTitle("Invoice");
|
||||||
|
$this->mpdf->SetAuthor("rprt-cli");
|
||||||
$this->mpdf->SetDisplayMode('fullpage');
|
$this->mpdf->SetDisplayMode('fullpage');
|
||||||
|
|
||||||
$this->mpdf->WriteHTML($html);
|
$this->mpdf->WriteHTML($html);
|
||||||
|
$this->mpdf->Output($this->getOutput(), Destination::FILE);
|
||||||
if (!$this->output) {
|
|
||||||
$this->output = $this->config->get('report.output', NULL) ?? readline('Enter output file path: ');
|
|
||||||
}
|
|
||||||
$this->mpdf->Output($this->output, Destination::FILE);
|
|
||||||
return file_exists($this->output);
|
return file_exists($this->output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getOutput() {
|
||||||
|
if (isset($this->output)) {
|
||||||
|
return $this->output;
|
||||||
|
}
|
||||||
|
$output = $this->config->get('export.output', NULL) ?? readline('Enter output file path: ');
|
||||||
|
$output = str_replace('[[month]]', date('F'), $output);
|
||||||
|
$output = str_replace('[[year]]', date('Y'), $output);
|
||||||
|
$this->output = $output;
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
public function setOutput(string $path) {
|
public function setOutput(string $path) {
|
||||||
$this->output = $path;
|
$this->output = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fromDataToPdf(array $data, array $tokens = []): bool {
|
public function fromDataToPdf(array $data, array $tokens = []): bool {
|
||||||
$template_path = $this->getTemplatePath();
|
$template_path = $this->getTemplatePath();
|
||||||
|
$tokens = $this->defaultTokens();
|
||||||
$tokens['table'] = $this->parsedDataToHtmlTable($data);
|
$tokens['table'] = $this->parsedDataToHtmlTable($data);
|
||||||
|
$tokens = $this->gatherTokensForTemplate($template_path, FALSE, $tokens);
|
||||||
$html = $this->replaceTokensInTemplate($template_path, $tokens);
|
$html = $this->replaceTokensInTemplate($template_path, $tokens);
|
||||||
$success = $this->pdfExport($html);
|
$success = $this->pdfExport($html);
|
||||||
return $success;
|
return $success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get default tokens.
|
||||||
|
*/
|
||||||
|
protected function defaultTokens(): array {
|
||||||
|
$tokens = [];
|
||||||
|
$tokens['today'] = date('j. m. y');
|
||||||
|
$month_ago = strtotime('1 month ago');
|
||||||
|
$tokens['number'] = date('m/y', $month_ago);
|
||||||
|
$tokens['date_start'] = date('1. m. y', $month_ago);
|
||||||
|
$tokens['date_end'] = date("Y-m-d", mktime(0, 0, 0, (int) date("m"), 0));
|
||||||
|
return $tokens;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue