diff --git a/.phive/phars.xml b/.phive/phars.xml
index 63a030f34ebaa167a4ac0c278a66d42d6f1d11e6..ebb5988ac5456a0286d35a530df2673a49c57c2b 100644
--- a/.phive/phars.xml
+++ b/.phive/phars.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <phive xmlns="https://phar.io/phive">
-  <phar name="phpstan" version="1.11.1" installed="1.11.1" 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"/>
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7275517f87ad09dcdc7cd4f6f79e2ed27d04cc5b 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -0,0 +1,391 @@
+parameters:
+	ignoreErrors:
+		-
+			message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:hasPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#"
+			count: 1
+			path: ajax/memberships/canUnlock.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getUniqueGroupIds\\(\\)\\.$#"
+			count: 1
+			path: ajax/memberships/get.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getBackendViewData\\(\\)\\.$#"
+			count: 1
+			path: ajax/memberships/getView.php
+
+		-
+			message: "#^Call to static method addString\\(\\) on an unknown class QUI\\\\Watcher\\.$#"
+			count: 1
+			path: ajax/memberships/lock.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:createProduct\\(\\)\\.$#"
+			count: 1
+			path: ajax/memberships/products/createMembershipProducts.php
+
+		-
+			message: "#^Access to constant FIELD_PRODUCT_NO on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#"
+			count: 1
+			path: ajax/memberships/products/getMembershipProducts.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getProducts\\(\\)\\.$#"
+			count: 1
+			path: ajax/memberships/products/getMembershipProducts.php
+
+		-
+			message: "#^Call to method getFieldValue\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: ajax/memberships/products/getMembershipProducts.php
+
+		-
+			message: "#^Call to method getId\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: ajax/memberships/products/getMembershipProducts.php
+
+		-
+			message: "#^Call to method getTitle\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: ajax/memberships/products/getMembershipProducts.php
+
+		-
+			message: "#^PHPDoc tag @var for variable \\$Product contains unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: ajax/memberships/products/getMembershipProducts.php
+
+		-
+			message: "#^Call to static method addString\\(\\) on an unknown class QUI\\\\Watcher\\.$#"
+			count: 1
+			path: ajax/memberships/unlock.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getTitle\\(\\)\\.$#"
+			count: 1
+			path: ajax/memberships/users/create.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:searchUsers\\(\\)\\.$#"
+			count: 2
+			path: ajax/memberships/users/getArchiveList.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:searchUsers\\(\\)\\.$#"
+			count: 2
+			path: ajax/memberships/users/getList.php
+
+		-
+			message: "#^Parameter \\#2 \\$value of method QUI\\\\Users\\\\User\\:\\:setAttribute\\(\\) expects array\\|int\\|string, true given\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Cron.php
+
+		-
+			message: "#^Call to static method getCategory\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Categories\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Call to static method getField\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getDefaultMembership\\(\\) should return QUI\\\\Memberships\\\\Membership\\|false but returns QUI\\\\CRUD\\\\Child\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getProductCategory\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Interfaces\\\\CategoryInterface\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getProductMembershipField\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:getProductMembershipFlagField\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Handler\\:\\:search\\(\\) should return array but returns int\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Variable \\$whereOr in empty\\(\\) always exists and is not falsy\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Handler.php
+
+		-
+			message: "#^Access to constant FIELD_AUTO_EXTEND on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Access to constant FIELD_DURATION on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Access to constant FIELD_INVOICE_INTERVAL on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Access to constant FIELD_MIN_DURATION on an unknown class QUI\\\\ERP\\\\Plans\\\\Handler\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Access to constant FIELD_SHORT_DESC on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Access to constant FIELD_TITLE on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getGroupIds\\(\\)\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to method deactivate\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to method getField\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to method getId\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to method save\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to method search\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Search\\\\BackendSearch\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to method setOwnFieldStatus\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to method setValue\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to static method createProduct\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Products\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to static method getField\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Fields\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to static method getProduct\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Products\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Cannot call method getId\\(\\) on QUI\\\\ERP\\\\Products\\\\Field\\\\Field\\|false\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Class QUI\\\\ERP\\\\Plans\\\\PlanProduct not found\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Instantiated class QUI\\\\ERP\\\\Products\\\\Search\\\\BackendSearch not found\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:addUser\\(\\) should return QUI\\\\Memberships\\\\Users\\\\MembershipUser but returns QUI\\\\CRUD\\\\Child\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:createProduct\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:getGroupIds\\(\\) should return array\\<int\\> but returns array\\<int, string\\>\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:getMembershipUser\\(\\) should return QUI\\\\Memberships\\\\Users\\\\MembershipUser but returns QUI\\\\CRUD\\\\Child\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Membership\\:\\:getProducts\\(\\) has invalid return type QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^PHPDoc tag @var for variable \\$Product contains unknown class QUI\\\\ERP\\\\Products\\\\Product\\\\Product\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Parameter \\#2 \\$PermissionUser of method QUI\\\\Memberships\\\\Users\\\\Handler\\:\\:createChild\\(\\) expects QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:checkPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Ternary operator condition is always true\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Variable \\$where in empty\\(\\) always exists and is not falsy\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Membership.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:calcEndDate\\(\\)\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/Handler.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:getMembershipUser\\(\\)\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/Handler.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:hasMembershipUserId\\(\\)\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/Handler.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Users\\\\Handler\\:\\:getMembershipUsersByUserId\\(\\) should return array\\<QUI\\\\Memberships\\\\Users\\\\MembershipUser\\> but returns array\\<int\\<0, max\\>, QUI\\\\CRUD\\\\Child\\>\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/Handler.php
+
+		-
+			message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:checkPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/Handler.php
+
+		-
+			message: "#^Call to an undefined method QUI\\\\CRUD\\\\Child\\:\\:hasMembershipUserId\\(\\)\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to method getCurrentCancelTerminationDate\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to method getCycleEndDate\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to method getNextCycleEndDate\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to method getPeriodOfNoticeInterval\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to method isInPeriodOfNotice\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to static method getInstance\\(\\) on an unknown class QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Handler\\.$#"
+			count: 3
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to static method getProduct\\(\\) on an unknown class QUI\\\\ERP\\\\Products\\\\Handler\\\\Products\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^If condition is always true\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Method QUI\\\\Memberships\\\\Users\\\\MembershipUser\\:\\:getContract\\(\\) has invalid return type QUI\\\\ERP\\\\Accounting\\\\Contracts\\\\Contract\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^PHPDoc tag @param references unknown parameter\\: \\$withPermission$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Parameter \\#2 \\$User of static method QUI\\\\Permissions\\\\Permission\\:\\:checkPermission\\(\\) expects bool\\|QUI\\\\Users\\\\User\\|null, QUI\\\\Interfaces\\\\Users\\\\User given\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Parameter \\#2 \\$msg of method QUI\\\\Memberships\\\\Users\\\\MembershipUser\\:\\:addHistoryEntry\\(\\) expects string, array\\<string, string\\> given\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Parameter \\#2 \\$val of method QUI\\\\QDOM\\:\\:setAttribute\\(\\) expects array\\|bool\\|object\\|string, int given\\.$#"
+			count: 2
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Parameter \\#2 \\$val of method QUI\\\\QDOM\\:\\:setAttribute\\(\\) expects array\\|bool\\|object\\|string, null given\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Unreachable statement \\- code above always terminates\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Users/MembershipUser.php
+
+		-
+			message: "#^Call to function is_string\\(\\) with int will always evaluate to false\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Utils.php
+
+		-
+			message: "#^Result of && is always false\\.$#"
+			count: 1
+			path: src/QUI/Memberships/Utils.php
diff --git a/phpstan.dist.neon b/phpstan.dist.neon
index 0f467fc82e5773506907e75793d1196cfcbcff9d..439055b13f6086aae1a0524df549fe00752abe4e 100644
--- a/phpstan.dist.neon
+++ b/phpstan.dist.neon
@@ -2,7 +2,7 @@ includes:
 	- phpstan-baseline.neon
 
 parameters:
-    level: 8
+    level: 5
     paths:
         - src
         - ajax
@@ -10,4 +10,6 @@ parameters:
         - src/QUI/Memberships/Events.php
         - src/QUI/Memberships/Controls/Profile/Memberships.php
         - src/QUI/Memberships/Products/MembershipField.php
+    bootstrapFiles:
+        - tests/phpstan-bootstrap.php
     tipsOfTheDay: false