diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..9ab59b180fb670006ac910a2bc4524a1376dcea0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ + +# Ignore developer files when exporting +.gitattributes export-ignore +.gitignore export-ignore +.gitlab-ci.yml export-ignore +.phive export-ignore +captainhook.json export-ignore +phpcs.xml.dist export-ignore +phpstan-baseline.neon export-ignore +phpstan.dist.neon export-ignore +phpunit.dist.xml export-ignore +tests export-ignore + +# Explicitly set file type and line endings for PHP files, improves git diff output +*.php text eol=lf diff=php \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b9f7c5c4723a7ff60166164bae8afaeec189067a --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ + +tools/ + +phpstan.neon + +.phpunit.result.cache + +phpunit.xml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b8d20acb6c365ad8036a7b36d47dabd876d08efa..b5a64b401e554341447c74d7cf93a89ac95a3fdb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,17 @@ include: - - project: 'quiqqer/stabilization/semantic-release' - file: '/ci-templates/.gitlab-ci.yml' + - component: dev.quiqqer.com/quiqqer/stabilization/ci-cd-components/quiqqer-package-bundle/quiqqer-package-bundle@main + +# Remove the entire phpunit-php8.1 block, to allow PHPUnit to run on PHP 8.1 in your pipeline +phpunit-php8.1: + rules: + - when: never + +# Remove the entire phpunit-php8.2 block, to allow PHPUnit to run on PHP 8.2 in your pipeline +phpunit-php8.2: + rules: + - when: never + +# Remove the entire phpunit-php8.3 block, to allow PHPUnit to run on PHP 8.3 in your pipeline +phpunit-php8.3: + rules: + - when: never \ No newline at end of file diff --git a/.phive/phars.xml b/.phive/phars.xml index a1315a09b4adad780a9c5e52f74835c708c5c7d5..5bfa092bfad10dad9d23240281a5a2041acb815b 100644 --- a/.phive/phars.xml +++ b/.phive/phars.xml @@ -1,4 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <phive xmlns="https://phar.io/phive"> - <phar name="phpstan" version="^1.10.67" installed="1.10.67" location="./tools/phpstan" copy="false"/> + <phar name="phpstan" version="1.11.8" installed="1.11.8" location="./tools/phpstan" copy="false"/> + <phar name="phpunit" version="^10.5.20" installed="10.5.20" location="./tools/phpunit" copy="false"/> + <phar name="phpcs" version="^3.10.1" installed="3.10.1" location="./tools/phpcs" copy="false"/> + <phar name="phpcbf" version="^3.10.1" installed="3.10.1" location="./tools/phpcbf" copy="false"/> + <phar name="captainhook" version="^5.23.3" installed="5.23.3" location="./tools/captainhook" copy="false"/> </phive> diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..4a69a59b440e5beec561eca1e341509bd5a18688 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing + +This package follows the [QUIQQER contribution guidelines](https://dev.quiqqer.com/quiqqer/stabilization/documentation/-/wikis/home). \ No newline at end of file diff --git a/captainhook.json b/captainhook.json new file mode 100644 index 0000000000000000000000000000000000000000..3702e1a358868bedd5ff4c7eae40bb1abb589267 --- /dev/null +++ b/captainhook.json @@ -0,0 +1,13 @@ +{ + "pre-commit": { + "enabled": true, + "actions": [ + { + "action": "\\CaptainHook\\App\\Hook\\PHP\\Action\\Linting" + }, + { + "action": "composer test" + } + ] + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index 18460b362545e3c1fb9d13fa9d27155c673f8f2d..8165b1d527f3df9dd0d08069c2d2168a9160c19e 100644 --- a/composer.json +++ b/composer.json @@ -1,40 +1,82 @@ { - "name": "quiqqer/erp", - "type": "quiqqer-application", - "description": "The QUIQQER ERP module bundles all QUIQQER modules which you need for a \nERP (Enterprise Resource Planning) system.", - "license": [ - "GPL-3.0+", - "PCSG QEL-1.0" - ], - "authors": [ - { - "name": "Henning Leutz", - "email": "leutz@pcsg.de", - "homepage": "https://www.pcsg.de", - "role": "Developer" + "name": "quiqqer/erp", + "type": "quiqqer-application", + "description": "The QUIQQER ERP module bundles all QUIQQER modules which you need for a \nERP (Enterprise Resource Planning) system.", + "license": [ + "GPL-3.0+", + "PCSG QEL-1.0" + ], + "authors": [ + { + "name": "Henning Leutz", + "email": "leutz@pcsg.de", + "homepage": "https://www.pcsg.de", + "role": "Developer" + } + ], + "support": { + "email": "support@pcsg.de", + "url": "https://www.pcsg.de" + }, + "require": { + "php": "^8", + "quiqqer/core": "^2", + "quiqqer/utils": "^2", + "quiqqer/watcher": "^2", + "quiqqer/translator": "^2", + "quiqqer/employee": "^2", + "quiqqer/customer": "^2", + "quiqqer/qui-php": "^2", + "quiqqer/countries": "^2", + "quiqqer/frontend-users": "^2", + "quiqqer/erp-accounting-templates": "^2", + "quiqqer/areas": "^2" + }, + "autoload": { + "psr-4": { + "QUI\\ERP\\": "src/QUI/ERP" + } + }, + "scripts": { + "test": [ + "@dev:lint", + "@dev:phpunit" + ], + "dev:phpunit": "./tools/phpunit", + "dev:lint": [ + "@dev:lint:phpstan", + "@dev:lint:style" + ], + "dev:lint:phpstan": "./tools/phpstan", + "dev:lint:style": "./tools/phpcs", + "dev:lint:style:fix": "./tools/phpcbf", + "dev:init": [ + "@dev:init:check-requirements", + "@dev:init:tools", + "@dev:init:git-hooks" + ], + "dev:init:check-requirements": [ + "which composer > /dev/null || (echo 'Error: composer has to be globally installed'; exit 1)", + "which phive > /dev/null || (echo 'Error: PHIVE has to be globally installed'; exit 1)" + ], + "dev:init:tools": "phive install --temporary", + "dev:init:git-hooks": "./tools/captainhook install --only-enabled --force" + }, + "scripts-aliases": { + "test": [ + "dev:test" + ] + }, + "scripts-descriptions": { + "test": "Runs linting, static analysis, and unit tests.", + "dev:phpunit": "Run PHPUnit test suites", + "dev:lint": "Run PHPStan and code style check", + "dev:lint:phpstan": "Run PHPStan", + "dev:lint:style": "Run code style check (PHP_CodeSniffer)", + "dev:lint:style:fix": "Try to fix code style errors automatically", + "dev:init": "Initialize the developer tooling (tools and git hooks)", + "dev:init:check-requirements": "Check if the necessary requirements are met", + "dev:init:tools": "Install all developer tools (requires PHIVE)", + "dev:init:git-hooks": "Install all git hooks (may require tools to be installed)" } - ], - "support": { - "email": "support@pcsg.de", - "url": "https://www.pcsg.de" - }, - "require": { - "php": "^8", - "quiqqer/core": "^2", - "quiqqer/utils": "^2", - "quiqqer/watcher": "^2", - "quiqqer/translator": "^2", - "quiqqer/employee": "^2", - "quiqqer/customer": "^2", - "quiqqer/qui-php": "^2", - "quiqqer/countries": "^2", - "quiqqer/frontend-users": "^2", - "quiqqer/erp-accounting-templates": "^2", - "quiqqer/areas": "^2" - }, - "autoload": { - "psr-4": { - "QUI\\ERP\\": "src/QUI/ERP" - } - } -} +} \ No newline at end of file diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..03a5e5e0db9da28cd4d1114d41973c77e059d3fb 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -0,0 +1,351 @@ +parameters: + ignoreErrors: + - + message: "#^Else branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: ajax/calcBruttoPrice.php + + - + message: "#^Elseif branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: ajax/calcBruttoPrice.php + + - + message: "#^Instanceof between \\*NEVER\\* and QUI\\\\ERP\\\\Tax\\\\TaxEntry will always evaluate to false\\.$#" + count: 1 + path: ajax/calcBruttoPrice.php + + - + message: "#^Binary operation \"\\*\" between string and \\(float\\|int\\) results in an error\\.$#" + count: 1 + path: ajax/calcNettoPrice.php + + - + message: "#^Else branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: ajax/calcNettoPrice.php + + - + message: "#^Elseif branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: ajax/calcNettoPrice.php + + - + message: "#^Instanceof between \\*NEVER\\* and QUI\\\\ERP\\\\Tax\\\\TaxEntry will always evaluate to false\\.$#" + count: 1 + path: ajax/calcNettoPrice.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, float given\\.$#" + count: 1 + path: ajax/calcNettoPrice.php + + - + message: "#^Parameter \\#2 \\$string of function explode expects string, float given\\.$#" + count: 1 + path: ajax/calcNettoPrice.php + + - + message: "#^Method QUI\\\\ERP\\\\ErpEntityInterface\\:\\:getCustomerFiles\\(\\) invoked with 1 parameter, 0 required\\.$#" + count: 1 + path: ajax/customerFiles/getFiles.php + + - + message: "#^Parameter \\#9 \\$attachedMediaFiles of static method QUI\\\\ERP\\\\Output\\\\Output\\:\\:sendPdfViaMail\\(\\) expects array\\<QUI\\\\Projects\\\\Media\\\\File\\|QUI\\\\Projects\\\\Media\\\\Image\\>, array\\<int\\<0, max\\>, QUI\\\\Interfaces\\\\Projects\\\\Media\\\\File\\> given\\.$#" + count: 1 + path: ajax/output/sendMail.php + + - + message: "#^Method QUI\\\\ERP\\\\Accounting\\\\ArticleList\\:\\:getOrder\\(\\) has invalid return type QUI\\\\ERP\\\\Order\\\\AbstractOrder\\.$#" + count: 2 + path: src/QUI/ERP/Accounting/ArticleList.php + + - + message: "#^Parameter \\$Order of method QUI\\\\ERP\\\\Accounting\\\\ArticleList\\:\\:setOrder\\(\\) has invalid type QUI\\\\ERP\\\\Order\\\\AbstractOrder\\.$#" + count: 2 + path: src/QUI/ERP/Accounting/ArticleList.php + + - + message: "#^Property QUI\\\\ERP\\\\Accounting\\\\ArticleList\\:\\:\\$Order has unknown class QUI\\\\ERP\\\\Order\\\\AbstractOrder as its type\\.$#" + count: 2 + path: src/QUI/ERP/Accounting/ArticleList.php + + - + message: "#^Call to method getAttribute\\(\\) on an unknown class QUI\\\\ERP\\\\Order\\\\AbstractOrder\\.$#" + count: 1 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Call to method getDeliveryAddress\\(\\) on an unknown class QUI\\\\ERP\\\\Order\\\\AbstractOrder\\.$#" + count: 1 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Class QUI\\\\ERP\\\\Order\\\\AbstractOrder not found\\.$#" + count: 1 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Offset 0 on array\\<string, mixed\\> in isset\\(\\) does not exist\\.$#" + count: 1 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Offset 0 on array\\<string, string\\> in isset\\(\\) does not exist\\.$#" + count: 1 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Parameter \\$Invoice of method QUI\\\\ERP\\\\Accounting\\\\Calc\\:\\:calculateInvoicePayments\\(\\) has invalid type QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Invoice\\.$#" + count: 2 + path: src/QUI/ERP/Accounting/Calc.php + + - + message: "#^Parameter \\$Transaction of method QUI\\\\ERP\\\\ErpTransactionsInterface\\:\\:addTransaction\\(\\) has invalid type QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Transaction\\.$#" + count: 1 + path: src/QUI/ERP/ErpTransactionsInterface.php + + - + message: "#^Parameter \\$Transaction of method QUI\\\\ERP\\\\ErpTransactionsInterface\\:\\:linkTransaction\\(\\) has invalid type QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Transaction\\.$#" + count: 1 + path: src/QUI/ERP/ErpTransactionsInterface.php + + - + message: "#^Parameter \\#1 \\$code of method QUI\\\\Interfaces\\\\Users\\\\User\\:\\:activate\\(\\) expects string, false given\\.$#" + count: 1 + path: src/QUI/ERP/Manufacturers.php + + - + message: "#^Strict comparison using \\=\\=\\= between mixed and '' will always evaluate to false\\.$#" + count: 2 + path: src/QUI/ERP/Manufacturers.php + + - + message: "#^Call to method createPDF\\(\\) on an unknown class QUI\\\\HtmlToPdf\\\\Document\\.$#" + count: 1 + path: src/QUI/ERP/Output/Output.php + + - + message: "#^Method QUI\\\\ERP\\\\Output\\\\Output\\:\\:getDocumentPdf\\(\\) has invalid return type QUI\\\\HtmlToPdf\\\\Document\\.$#" + count: 2 + path: src/QUI/ERP/Output/Output.php + + - + message: "#^Call to method setContentHTML\\(\\) on an unknown class QUI\\\\HtmlToPdf\\\\Document\\.$#" + count: 1 + path: src/QUI/ERP/Output/OutputTemplate.php + + - + message: "#^Call to method setFooterHTML\\(\\) on an unknown class QUI\\\\HtmlToPdf\\\\Document\\.$#" + count: 1 + path: src/QUI/ERP/Output/OutputTemplate.php + + - + message: "#^Call to method setHeaderHTML\\(\\) on an unknown class QUI\\\\HtmlToPdf\\\\Document\\.$#" + count: 1 + path: src/QUI/ERP/Output/OutputTemplate.php + + - + message: "#^Instantiated class QUI\\\\HtmlToPdf\\\\Document not found\\.$#" + count: 1 + path: src/QUI/ERP/Output/OutputTemplate.php + + - + message: "#^Method QUI\\\\ERP\\\\Output\\\\OutputTemplate\\:\\:getPDFDocument\\(\\) has invalid return type QUI\\\\HtmlToPdf\\\\Document\\.$#" + count: 2 + path: src/QUI/ERP/Output/OutputTemplate.php + + - + message: "#^Call to method getAmountFormatted\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Transaction\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getAttribute\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Invoice\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getAttribute\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\InvoiceTemporary\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getAttribute\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Offers\\\\Offer\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getDate\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Transaction\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getHash\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Offers\\\\Offer\\.$#" + count: 3 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getHash\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Transaction\\.$#" + count: 2 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getHistory\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Invoice\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getHistory\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\InvoiceTemporary\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getHistory\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Offers\\\\Offer\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getPrefixedNumber\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Invoice\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getPrefixedNumber\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\InvoiceTemporary\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getUUID\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Invoice\\.$#" + count: 2 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to method getUUID\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\InvoiceTemporary\\.$#" + count: 2 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Offers\\\\Handler\\.$#" + count: 3 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Order\\\\Handler\\.$#" + count: 2 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to static method getSalesOrder\\(\\) on an unknown class QUI\\\\ERP\\\\SalesOrders\\\\Handler\\.$#" + count: 2 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to static method getTableSalesOrders\\(\\) on an unknown class QUI\\\\ERP\\\\SalesOrders\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Invoice not found\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\InvoiceTemporary not found\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Method QUI\\\\ERP\\\\Process\\:\\:getInvoices\\(\\) has invalid return type QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Invoice\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Method QUI\\\\ERP\\\\Process\\:\\:getInvoices\\(\\) has invalid return type QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\InvoiceTemporary\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Method QUI\\\\ERP\\\\Process\\:\\:getOffers\\(\\) has invalid return type QUI\\\\ERP\\\\Accounting\\\\Offers\\\\Offer\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Method QUI\\\\ERP\\\\Process\\:\\:getOrder\\(\\) has invalid return type QUI\\\\ERP\\\\Order\\\\Order\\.$#" + count: 2 + path: src/QUI/ERP/Process.php + + - + message: "#^Method QUI\\\\ERP\\\\Process\\:\\:getOrder\\(\\) has invalid return type QUI\\\\ERP\\\\Order\\\\OrderInProcess\\.$#" + count: 2 + path: src/QUI/ERP/Process.php + + - + message: "#^Method QUI\\\\ERP\\\\Process\\:\\:getTransactions\\(\\) has invalid return type QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Transaction\\.$#" + count: 1 + path: src/QUI/ERP/Process.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Processes.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Offers\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Processes.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Order\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Processes.php + + - + message: "#^Call to static method getTableSalesOrders\\(\\) on an unknown class QUI\\\\ERP\\\\SalesOrders\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Processes.php + + - + message: "#^Call to static method table\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Factory\\.$#" + count: 1 + path: src/QUI/ERP/Processes.php + + - + message: "#^Dead catch \\- Exception is never thrown in the try block\\.$#" + count: 2 + path: src/QUI/ERP/Processes.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Payments\\\\Transactions\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Utils/Process.php + + - + message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Order\\\\Handler\\.$#" + count: 1 + path: src/QUI/ERP/Utils/Process.php + + - + message: "#^Call to static method getInvoiceByString\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Invoice\\\\Utils\\\\Invoice\\.$#" + count: 1 + path: src/QUI/ERP/Utils/Process.php diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 255fa86b89c4b3e84073f38e3ef65bb6bb192c3b..b8ce314ac3f62b7515de9d5a486f56f0f80333e3 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -10,6 +10,7 @@ parameters: - tests/phpstan-bootstrap.php treatPhpDocTypesAsCertain: false customRulesetUsed: true + reportUnmatchedIgnoredErrors: false services: - class: \PHPStan\Rules\Properties\TypesAssignedToPropertiesRule diff --git a/phpunit.dist.xml b/phpunit.dist.xml new file mode 100644 index 0000000000000000000000000000000000000000..f6c7becf0c12757beb871a9333e2d81e02aa7cae --- /dev/null +++ b/phpunit.dist.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<phpunit bootstrap="tests/phpunit-bootstrap.php"> + <testsuites> + <testsuite name="Tests"> + <directory>tests/</directory> + </testsuite> + </testsuites> +</phpunit> diff --git a/src/QUI/ERP/Accounting/ArticleList.php b/src/QUI/ERP/Accounting/ArticleList.php index 3409713d9404e31eb6a0e6f594689d658aa93048..fe31ee4fc461954242ec7d8c93d377ee64eba6e5 100644 --- a/src/QUI/ERP/Accounting/ArticleList.php +++ b/src/QUI/ERP/Accounting/ArticleList.php @@ -552,8 +552,7 @@ public function renderForMail(): string public function toHTMLWithCSS( bool|string $template = false, bool|string $articleTemplate = false - ): string - { + ): string { return $this->toUniqueList()->toHTMLWithCSS($template, $articleTemplate); } diff --git a/src/QUI/ERP/Accounting/ArticleListUnique.php b/src/QUI/ERP/Accounting/ArticleListUnique.php index 05254629eb9d6fcc25c7514c72104b45052bb181..64a421da958d26f9e55702a6fa9f35ce0c0a107f 100644 --- a/src/QUI/ERP/Accounting/ArticleListUnique.php +++ b/src/QUI/ERP/Accounting/ArticleListUnique.php @@ -560,8 +560,7 @@ public function toMailHTML(): string public function toHTMLWithCSS( bool|string $template = false, bool|string $articleTemplate = false - ): string - { + ): string { $style = '<style>'; $style .= file_get_contents(dirname(__FILE__) . '/ArticleList.css'); $style .= '</style>'; @@ -581,8 +580,7 @@ public function toHTMLWithCSS( public function render( bool|string $template = false, bool|string $articleTemplate = false - ): string - { + ): string { return $this->toHTMLWithCSS($template, $articleTemplate); } diff --git a/src/QUI/ERP/Accounting/Calc.php b/src/QUI/ERP/Accounting/Calc.php index 7d36657777a3777eac00d5952efcb641ea44c6b8..fa79929ed8850e317d3a60454aabbfd4aac98df6 100644 --- a/src/QUI/ERP/Accounting/Calc.php +++ b/src/QUI/ERP/Accounting/Calc.php @@ -14,7 +14,6 @@ use QUI\ERP\Currency\Currency; use QUI\ERP\Money\Price; use QUI\Interfaces\Users\User as UserInterface; - use QUI\Locale; use function array_map; diff --git a/src/QUI/ERP/EventHandler.php b/src/QUI/ERP/EventHandler.php index 56e021c1f2a75babcde82ea9329429704e4c3c2c..6c70d02267522165ae53d83b74d7b2f2dbb82138 100644 --- a/src/QUI/ERP/EventHandler.php +++ b/src/QUI/ERP/EventHandler.php @@ -19,9 +19,11 @@ use function dirname; use function explode; use function is_array; +use function is_object; use function is_string; use function json_decode; use function json_encode; +use function method_exists; /** * Class EventHandler @@ -415,17 +417,41 @@ public static function onSmartyInit(Smarty $Smarty): void /** * erp smarty function {getPrefixedNumber} * - * @example {erpGetPrefixedNumber assign=prefixedNumber var=$erpUUID} - * * @param array $params * @param $smarty * @return string + * @example {erpGetPrefixedNumber assign=prefixedNumber var=$erpUUID} + * */ public static function getPrefixedNumber(array $params, $smarty): string { $prefixedNumber = ''; - if (!empty($params['var'])) { + if (empty($params['var'])) { + return ''; + } + + $var = $params['var']; + + if (is_object($var)) { + if ($var instanceof ErpEntityInterface) { + $prefixedNumber = $var->getPrefixedNumber(); + } elseif (method_exists($var, 'getPrefixedNumber')) { + $prefixedNumber = $var->getPrefixedNumber(); + } elseif (method_exists($var, 'getId')) { + $prefixedNumber = $var->getId(); + } + } elseif (is_array($var) && isset($var['prefixedNumber'])) { + $prefixedNumber = $var['prefixedNumber']; + } elseif (is_array($var) && isset($var['id_str'])) { + $prefixedNumber = $var['id_str']; + } elseif (is_array($var) && isset($var['hash'])) { + try { + $Entity = (new Processes())->getEntity($var['hash']); + $prefixedNumber = $Entity->getPrefixedNumber(); + } catch (QUI\Exception) { + } + } else { try { $Entity = (new Processes())->getEntity($params['var']); $prefixedNumber = $Entity->getPrefixedNumber(); diff --git a/src/QUI/ERP/Process.php b/src/QUI/ERP/Process.php index a1ffb206f9414ef40a6c918c72f906353598494f..8afbb85b72c45ec5271b2bcaa6e1bbe8558cee3a 100644 --- a/src/QUI/ERP/Process.php +++ b/src/QUI/ERP/Process.php @@ -141,7 +141,7 @@ class_exists('QUI\ERP\Accounting\Invoice\Invoice') } } - if (class_exists('QUI\ERP\SalesOrders\SalesOrder')) { + if (class_exists('QUI\ERP\SalesOrders\Handler')) { $salesOrder = $Entity->getPaymentData('salesOrder'); if ($salesOrder) { @@ -154,6 +154,45 @@ class_exists('QUI\ERP\Accounting\Invoice\Invoice') } } + if (empty($groups)) { + if (class_exists('QUI\ERP\Order\Order')) { + foreach ($entities as $Entity) { + if (!($Entity instanceof QUI\ERP\Order\Order)) { + continue; + } + + $uuid = $Entity->getUUID(); + + $groups[$uuid][] = $Entity; + + if (class_exists('QUI\ERP\SalesOrders\Handler')) { + $salesOrder = $Entity->getPaymentData('salesOrder'); + + if ($salesOrder) { + try { + $groups[$uuid][] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['hash']); + } catch (QUI\Exception) { + } + } + } + } + } + } + + if (empty($groups)) { + if (class_exists('QUI\ERP\SalesOrders\SalesOrder')) { + foreach ($entities as $Entity) { + if (!($Entity instanceof QUI\ERP\SalesOrders\SalesOrder)) { + continue; + } + + $uuid = $Entity->getUUID(); + $groups[$uuid][] = $Entity; + } + } + } + + // not group $notGroup = []; $isInGroups = function (ErpEntityInterface $Entity) use ($groups) { @@ -852,6 +891,12 @@ public function getSalesOrders(): array return []; } + if (!class_exists('QUI\ERP\SalesOrders\Handler')) { + return []; + } + + $result = []; + try { $salesOrders = QUI::getDatabase()->fetch([ 'select' => 'id,hash,global_process_id,date', @@ -865,8 +910,6 @@ public function getSalesOrders(): array return []; } - $result = []; - foreach ($salesOrders as $salesOrder) { try { $result[] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['id']); @@ -874,6 +917,27 @@ public function getSalesOrders(): array } } + // drafts + try { + $salesOrderDrafts = QUI::getDatabase()->fetch([ + 'select' => 'id,hash,global_process_id,date', + 'from' => QUI\ERP\SalesOrders\Handler::getTableSalesOrderDrafts(), + 'where_or' => [ + 'global_process_id' => $this->processId, + 'hash' => $this->processId + ] + ]); + } catch (\Exception) { + return []; + } + + foreach ($salesOrderDrafts as $salesOrder) { + try { + $result[] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['id']); + } catch (\Exception) { + } + } + return $result; } diff --git a/src/QUI/ERP/Processes.php b/src/QUI/ERP/Processes.php index 8d3196dc685bd535a0a8b7ef92068437147e3dc1..ecb9a8666ff47268397e785bf7d9f8922b0111a2 100644 --- a/src/QUI/ERP/Processes.php +++ b/src/QUI/ERP/Processes.php @@ -57,6 +57,16 @@ public function getEntity($entityHash, $entityPlugin = false): ErpEntityInterfac } } + if ( + ($entityPlugin === false || $entityPlugin === 'quiqqer/dunning') + && class_exists('QUI\ERP\Accounting\Dunning\Handler') + ) { + try { + return QUI\ERP\Accounting\Dunning\Handler::getInstance()->getDunningProcess($entityHash); + } catch (\Exception) { + } + } + if ($entityPlugin === false || $entityPlugin === 'quiqqer/delivery-notes') { try { // @todo quiqqer/delivery-notes diff --git a/tests/phpunit-bootstrap.php b/tests/phpunit-bootstrap.php new file mode 100644 index 0000000000000000000000000000000000000000..eca92fd67bed8ae4ec424ed82d300119d792f042 --- /dev/null +++ b/tests/phpunit-bootstrap.php @@ -0,0 +1,11 @@ +<?php + +if (!defined('QUIQQER_SYSTEM')) { + define('QUIQQER_SYSTEM', true); +} + +if (!defined('QUIQQER_AJAX')) { + define('QUIQQER_AJAX', true); +} + +require_once __DIR__ . '/../../../../bootstrap.php'; diff --git a/tools/phpstan b/tools/phpstan deleted file mode 120000 index 54ee46842f744a4e7fbd1ebf83ebcb14059f7e15..0000000000000000000000000000000000000000 --- a/tools/phpstan +++ /dev/null @@ -1 +0,0 @@ -/home/hen/.phive/phars/phpstan-1.10.67.phar \ No newline at end of file