add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks - Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists - Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services - Add Microsoft OIDC SSO, API token management, and user lifecycle features - Add swagger-ui vendor integration and OpenAPI spec - Add production Docker setup and bin/ scripts - Update composer dependencies, config, templates, and frontend assets throughout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
namespace MintyPHP\Service\Org;
|
||||
|
||||
use MintyPHP\Repository\Org\DepartmentRepository;
|
||||
use MintyPHP\Repository\Tenant\TenantDepartmentRepository;
|
||||
use MintyPHP\Repository\Org\UserDepartmentRepository;
|
||||
use MintyPHP\Service\Settings\SettingService;
|
||||
use MintyPHP\Service\Tenant\TenantScopeService;
|
||||
@@ -31,6 +30,39 @@ class DepartmentService
|
||||
return DepartmentRepository::listByTenantIds($tenantIds);
|
||||
}
|
||||
|
||||
public static function groupActiveByTenantIds(array $tenantIds): array
|
||||
{
|
||||
$tenantIds = array_values(array_unique(array_map('intval', $tenantIds)));
|
||||
$tenantIds = array_values(array_filter($tenantIds, static fn ($id) => $id > 0));
|
||||
if (!$tenantIds) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$departments = self::listByTenantIds($tenantIds);
|
||||
if (!$departments) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$grouped = [];
|
||||
foreach ($departments as $department) {
|
||||
$tenantId = (int) ($department['tenant_id'] ?? 0);
|
||||
if ($tenantId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$grouped[$tenantId] ??= [];
|
||||
$grouped[$tenantId][] = $department;
|
||||
}
|
||||
|
||||
foreach ($grouped as &$items) {
|
||||
usort($items, static function (array $a, array $b): int {
|
||||
return strcmp((string) ($a['description'] ?? ''), (string) ($b['description'] ?? ''));
|
||||
});
|
||||
}
|
||||
unset($items);
|
||||
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
public static function listByIds(array $departmentIds): array
|
||||
{
|
||||
return DepartmentRepository::listByIds($departmentIds);
|
||||
@@ -79,6 +111,7 @@ class DepartmentService
|
||||
|
||||
$createdId = DepartmentRepository::create([
|
||||
'description' => $form['description'],
|
||||
'tenant_id' => $form['tenant_id'],
|
||||
'code' => $form['code'] ?: null,
|
||||
'cost_center' => $form['cost_center'] ?: null,
|
||||
'active' => $form['active'],
|
||||
@@ -91,7 +124,7 @@ class DepartmentService
|
||||
|
||||
$createdDepartment = DepartmentRepository::find((int) $createdId);
|
||||
$uuid = $createdDepartment['uuid'] ?? null;
|
||||
if (!empty($input['is_default']) && $createdId) {
|
||||
if (!empty($input['is_default'])) {
|
||||
SettingService::setDefaultDepartmentId((int) $createdId);
|
||||
}
|
||||
return ['ok' => true, 'form' => $form, 'warnings' => $warnings, 'uuid' => $uuid, 'id' => (int) $createdId];
|
||||
@@ -109,6 +142,7 @@ class DepartmentService
|
||||
|
||||
$updated = DepartmentRepository::update($departmentId, [
|
||||
'description' => $form['description'],
|
||||
'tenant_id' => $form['tenant_id'],
|
||||
'code' => $form['code'] ?: null,
|
||||
'cost_center' => $form['cost_center'] ?: null,
|
||||
'active' => $form['active'],
|
||||
@@ -122,12 +156,26 @@ class DepartmentService
|
||||
return ['ok' => true, 'form' => $form, 'warnings' => $warnings];
|
||||
}
|
||||
|
||||
public static function syncTenants(int $departmentId, array $tenantIds): int
|
||||
public static function syncTenant(int $departmentId, int $tenantId): int
|
||||
{
|
||||
$updated = TenantDepartmentRepository::replaceForDepartment($departmentId, $tenantIds);
|
||||
$updated = DepartmentRepository::setTenant($departmentId, $tenantId);
|
||||
if (!$updated) {
|
||||
return -1;
|
||||
}
|
||||
return self::cleanupUserAssignments($departmentId);
|
||||
}
|
||||
|
||||
public static function syncTenants(int $departmentId, array $tenantIds): int
|
||||
{
|
||||
$tenantId = (int) ($tenantIds[0] ?? 0);
|
||||
if ($tenantId <= 0) {
|
||||
return -1;
|
||||
}
|
||||
return self::syncTenant($departmentId, $tenantId);
|
||||
}
|
||||
|
||||
public static function cleanupUserAssignments(int $departmentId): int
|
||||
{
|
||||
return UserDepartmentRepository::removeInvalidForDepartment($departmentId);
|
||||
}
|
||||
|
||||
@@ -155,6 +203,7 @@ class DepartmentService
|
||||
{
|
||||
return [
|
||||
'description' => trim((string) ($input['description'] ?? '')),
|
||||
'tenant_id' => (int) ($input['tenant_id'] ?? 0),
|
||||
'code' => trim((string) ($input['code'] ?? '')),
|
||||
'cost_center' => trim((string) ($input['cost_center'] ?? '')),
|
||||
'active' => self::normalizeActive($input['active'] ?? 1),
|
||||
@@ -167,6 +216,9 @@ class DepartmentService
|
||||
if ($form['description'] === '') {
|
||||
$errors[] = t('Description cannot be empty');
|
||||
}
|
||||
if ((int) ($form['tenant_id'] ?? 0) <= 0) {
|
||||
$errors[] = t('Please select at least one tenant');
|
||||
}
|
||||
return $errors;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user