Darstellung alle Benutzer aktualisiert
This commit is contained in:
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"sqltools.connections": [
|
||||
{
|
||||
"mysqlOptions": {
|
||||
"authProtocol": "default",
|
||||
"enableSsl": "Disabled"
|
||||
},
|
||||
"ssh": "Disabled",
|
||||
"previewLimit": 50,
|
||||
"server": "mysql2f5b.netcup.net",
|
||||
"port": 3306,
|
||||
"driver": "MySQL",
|
||||
"username": "k25330_kaffeetest",
|
||||
"password": "k0Zg48~g75634",
|
||||
"database": "k25330_kaffeetest",
|
||||
"name": "kaffeeliste Test"
|
||||
}
|
||||
]
|
||||
}
|
||||
+201
-27
@@ -808,6 +808,68 @@ function app_members_support_payment_reference(PDO $pdo): bool
|
||||
return app_table_has_column($pdo, 'members', 'payment_reference');
|
||||
}
|
||||
|
||||
function app_ensure_member_rows_for_tenant(PDO $pdo, string $tenantId): void
|
||||
{
|
||||
if ($tenantId === '' || !scripts_table_exists($pdo, 'members') || !scripts_table_exists($pdo, 'tenant_users')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$missingRows = app_query_all(
|
||||
$pdo,
|
||||
<<<'SQL'
|
||||
SELECT
|
||||
tu.id AS tenant_user_id,
|
||||
tu.status AS tenant_user_status,
|
||||
u.email,
|
||||
u.display_name
|
||||
FROM tenant_users tu
|
||||
INNER JOIN users u ON u.id = tu.user_id
|
||||
LEFT JOIN members m ON m.tenant_user_id = tu.id AND m.tenant_id = tu.tenant_id
|
||||
WHERE tu.tenant_id = :tenant_id
|
||||
AND m.id IS NULL
|
||||
SQL,
|
||||
['tenant_id' => $tenantId]
|
||||
);
|
||||
|
||||
if ($missingRows === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
|
||||
foreach ($missingRows as $row) {
|
||||
$status = ((string) ($row['tenant_user_status'] ?? 'active')) === 'inactive' ? 'inactive' : 'active';
|
||||
$params = [
|
||||
'id' => app_uuid(),
|
||||
'tenant_id' => $tenantId,
|
||||
'tenant_user_id' => (string) ($row['tenant_user_id'] ?? ''),
|
||||
'display_name' => trim((string) ($row['display_name'] ?? '')) !== ''
|
||||
? trim((string) ($row['display_name'] ?? ''))
|
||||
: trim((string) ($row['email'] ?? 'Mitglied')),
|
||||
'email' => strtolower(trim((string) ($row['email'] ?? ''))),
|
||||
'status' => $status,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if (app_members_support_payment_reference($pdo)) {
|
||||
$params['payment_reference'] = null;
|
||||
app_execute(
|
||||
$pdo,
|
||||
'INSERT INTO members (id, tenant_id, tenant_user_id, display_name, email, payment_reference, status, created_at, updated_at) VALUES (:id, :tenant_id, :tenant_user_id, :display_name, :email, :payment_reference, :status, :created_at, :updated_at)',
|
||||
$params
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
app_execute(
|
||||
$pdo,
|
||||
'INSERT INTO members (id, tenant_id, tenant_user_id, display_name, email, status, created_at, updated_at) VALUES (:id, :tenant_id, :tenant_user_id, :display_name, :email, :status, :created_at, :updated_at)',
|
||||
$params
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function app_tenant_user_by_id(PDO $pdo, string $tenantUserId, string $tenantId): ?array
|
||||
{
|
||||
$paymentReferenceSelect = app_members_support_payment_reference($pdo)
|
||||
@@ -3086,15 +3148,45 @@ SQL,
|
||||
|
||||
function app_members_for_tenant(PDO $pdo, string $tenantId): array
|
||||
{
|
||||
app_ensure_member_rows_for_tenant($pdo, $tenantId);
|
||||
|
||||
$paymentReferenceSelect = app_members_support_payment_reference($pdo)
|
||||
? 'm.payment_reference,'
|
||||
: 'NULL AS payment_reference,';
|
||||
|
||||
$sql = <<<'SQL'
|
||||
$tenantUserSql = <<<'SQL'
|
||||
SELECT
|
||||
m.id,
|
||||
tu.id AS tenant_user_id,
|
||||
tu.user_id,
|
||||
COALESCE(m.display_name, u.display_name) AS display_name,
|
||||
COALESCE(m.email, u.email) AS email,
|
||||
__PAYMENT_REFERENCE__
|
||||
COALESCE(m.status, tu.status) AS status,
|
||||
u.display_name AS user_display_name,
|
||||
GROUP_CONCAT(DISTINCT r.name ORDER BY r.name SEPARATOR ', ') AS roles,
|
||||
GROUP_CONCAT(DISTINCT r.role_key ORDER BY r.role_key SEPARATOR ',') AS role_keys,
|
||||
COALESCE((
|
||||
SELECT SUM(le.amount)
|
||||
FROM ledger_entries le
|
||||
WHERE le.member_id = m.id
|
||||
AND le.tenant_id = tu.tenant_id
|
||||
), 0) AS current_balance
|
||||
FROM tenant_users tu
|
||||
INNER JOIN users u ON u.id = tu.user_id
|
||||
LEFT JOIN members m ON m.tenant_user_id = tu.id AND m.tenant_id = tu.tenant_id
|
||||
LEFT JOIN tenant_user_roles tur ON tur.tenant_user_id = tu.id
|
||||
LEFT JOIN roles r ON r.id = tur.role_id
|
||||
WHERE tu.tenant_id = :tenant_id
|
||||
GROUP BY m.id, tu.id, tu.user_id, m.display_name, m.email, payment_reference, m.status, tu.status, u.display_name, u.email
|
||||
ORDER BY COALESCE(m.display_name, u.display_name) ASC
|
||||
SQL;
|
||||
|
||||
$memberOnlySql = <<<'SQL'
|
||||
SELECT
|
||||
m.id,
|
||||
m.tenant_user_id,
|
||||
tu.user_id,
|
||||
m.display_name,
|
||||
m.email,
|
||||
__PAYMENT_REFERENCE__
|
||||
@@ -3109,16 +3201,70 @@ SELECT
|
||||
AND le.tenant_id = m.tenant_id
|
||||
), 0) AS current_balance
|
||||
FROM members m
|
||||
LEFT JOIN tenant_users tu ON tu.id = m.tenant_user_id
|
||||
LEFT JOIN tenant_users tu ON tu.id = m.tenant_user_id AND tu.tenant_id = m.tenant_id
|
||||
LEFT JOIN users u ON u.id = tu.user_id
|
||||
LEFT JOIN tenant_user_roles tur ON tur.tenant_user_id = tu.id
|
||||
LEFT JOIN roles r ON r.id = tur.role_id
|
||||
WHERE m.tenant_id = :tenant_id
|
||||
GROUP BY m.id, tu.id, tu.user_id, m.display_name, m.email, payment_reference, m.status, u.display_name
|
||||
AND (
|
||||
m.tenant_user_id IS NULL
|
||||
OR tu.id IS NULL
|
||||
)
|
||||
GROUP BY m.id, m.tenant_user_id, tu.user_id, m.display_name, m.email, payment_reference, m.status, u.display_name
|
||||
ORDER BY m.display_name ASC
|
||||
SQL;
|
||||
|
||||
return app_query_all($pdo, str_replace('__PAYMENT_REFERENCE__', $paymentReferenceSelect, $sql), ['tenant_id' => $tenantId]);
|
||||
$rows = app_query_all(
|
||||
$pdo,
|
||||
str_replace('__PAYMENT_REFERENCE__', $paymentReferenceSelect, $tenantUserSql),
|
||||
['tenant_id' => $tenantId]
|
||||
);
|
||||
|
||||
foreach (
|
||||
app_query_all(
|
||||
$pdo,
|
||||
str_replace('__PAYMENT_REFERENCE__', $paymentReferenceSelect, $memberOnlySql),
|
||||
['tenant_id' => $tenantId]
|
||||
) as $row
|
||||
) {
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
$deduped = [];
|
||||
foreach ($rows as $row) {
|
||||
$id = trim((string) ($row['id'] ?? ''));
|
||||
$tenantUserId = trim((string) ($row['tenant_user_id'] ?? ''));
|
||||
$email = strtolower(trim((string) ($row['email'] ?? '')));
|
||||
$displayName = trim((string) ($row['display_name'] ?? ''));
|
||||
$key = $id !== ''
|
||||
? 'member:' . $id
|
||||
: ($tenantUserId !== ''
|
||||
? 'tenant-user:' . $tenantUserId
|
||||
: ($email !== '' ? 'email:' . $email : 'name:' . $displayName));
|
||||
|
||||
if (!isset($deduped[$key])) {
|
||||
$deduped[$key] = $row;
|
||||
continue;
|
||||
}
|
||||
|
||||
$existing = $deduped[$key];
|
||||
$existingHasMemberId = trim((string) ($existing['id'] ?? '')) !== '';
|
||||
$rowHasMemberId = $id !== '';
|
||||
if (!$existingHasMemberId && $rowHasMemberId) {
|
||||
$deduped[$key] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$result = array_values($deduped);
|
||||
usort(
|
||||
$result,
|
||||
static fn(array $left, array $right): int => strcasecmp(
|
||||
trim((string) ($left['display_name'] ?? '')),
|
||||
trim((string) ($right['display_name'] ?? ''))
|
||||
)
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function app_normalize_datetime_input(?string $value): string
|
||||
@@ -3205,32 +3351,50 @@ SQL,
|
||||
function app_members_for_scope(PDO $pdo, string $tenantId, string $scope = 'all'): array
|
||||
{
|
||||
$coffeeActiveSql = app_finance_entry_active_sql($pdo, 'coffee_entries', 'ce');
|
||||
$rows = app_query_all(
|
||||
$members = array_values(array_filter(
|
||||
app_members_for_tenant($pdo, $tenantId),
|
||||
static function (array $member): bool {
|
||||
$status = strtolower(trim((string) ($member['status'] ?? 'active')));
|
||||
return !in_array($status, ['inactive', 'disabled', 'archived'], true);
|
||||
}
|
||||
));
|
||||
|
||||
if ($members === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$recentStrokeRows = app_query_all(
|
||||
$pdo,
|
||||
str_replace(
|
||||
'__COFFEE_ACTIVE__',
|
||||
$coffeeActiveSql,
|
||||
<<<'SQL'
|
||||
SELECT
|
||||
m.id,
|
||||
m.display_name,
|
||||
COALESCE((
|
||||
SELECT SUM(ce.strokes)
|
||||
FROM coffee_entries ce
|
||||
WHERE ce.tenant_id = m.tenant_id
|
||||
AND ce.member_id = m.id
|
||||
AND __COFFEE_ACTIVE__
|
||||
AND ce.booked_at >= DATE_SUB(CURRENT_DATE(), INTERVAL 100 DAY)
|
||||
), 0) AS recent_strokes
|
||||
FROM members m
|
||||
WHERE m.tenant_id = :tenant_id
|
||||
AND m.status = 'active'
|
||||
ORDER BY m.display_name ASC
|
||||
SQL,
|
||||
ce.member_id,
|
||||
COALESCE(SUM(ce.strokes), 0) AS recent_strokes
|
||||
FROM coffee_entries ce
|
||||
WHERE ce.tenant_id = :tenant_id
|
||||
AND __COFFEE_ACTIVE__
|
||||
AND ce.booked_at >= DATE_SUB(CURRENT_DATE(), INTERVAL 100 DAY)
|
||||
GROUP BY ce.member_id
|
||||
SQL
|
||||
),
|
||||
['tenant_id' => $tenantId]
|
||||
);
|
||||
|
||||
$recentStrokeMap = [];
|
||||
foreach ($recentStrokeRows as $row) {
|
||||
$recentStrokeMap[(string) ($row['member_id'] ?? '')] = (int) ($row['recent_strokes'] ?? 0);
|
||||
}
|
||||
|
||||
$rows = array_map(
|
||||
static function (array $member) use ($recentStrokeMap): array {
|
||||
$member['recent_strokes'] = $recentStrokeMap[(string) ($member['id'] ?? '')] ?? 0;
|
||||
return $member;
|
||||
},
|
||||
$members
|
||||
);
|
||||
|
||||
if ($scope === 'front') {
|
||||
return array_values(array_filter($rows, static fn(array $row): bool => (int) ($row['recent_strokes'] ?? 0) >= 10));
|
||||
}
|
||||
@@ -3279,16 +3443,26 @@ function app_paypal_amount_links(array $settings, float $balance): array
|
||||
|
||||
function app_ledger_for_tenant(PDO $pdo, string $tenantId): array
|
||||
{
|
||||
$coffeeStatusSelect = app_finance_entries_support_status($pdo, 'coffee_entries')
|
||||
$coffeeSupportsStatus = app_finance_entries_support_status($pdo, 'coffee_entries');
|
||||
$paymentSupportsStatus = app_finance_entries_support_status($pdo, 'payment_entries');
|
||||
|
||||
$coffeeStatusSelect = $coffeeSupportsStatus
|
||||
? 'ce.status AS coffee_reference_status,'
|
||||
: "'booked' AS coffee_reference_status,";
|
||||
$coffeeCancelledSelect = app_finance_entries_support_status($pdo, 'coffee_entries')
|
||||
$coffeeCancelledSelect = $coffeeSupportsStatus
|
||||
? 'ce.cancelled_at AS coffee_reference_cancelled_at,'
|
||||
: 'NULL AS coffee_reference_cancelled_at,';
|
||||
$paymentStatusSelect = app_finance_entries_support_status($pdo, 'payment_entries')
|
||||
$paymentStatusSelect = $paymentSupportsStatus
|
||||
? 'pe.status AS payment_reference_status, pe.cancelled_at AS payment_cancelled_at,'
|
||||
: "'booked' AS payment_reference_status, NULL AS payment_cancelled_at,";
|
||||
$referenceStatusSql = app_finance_entries_support_status($pdo, 'coffee_entries') || app_finance_entries_support_status($pdo, 'payment_entries')
|
||||
$referenceCancelledAtSql = match (true) {
|
||||
$coffeeSupportsStatus && $paymentSupportsStatus => 'COALESCE(ce.cancelled_at, pe.cancelled_at) AS reference_cancelled_at,',
|
||||
$coffeeSupportsStatus => 'ce.cancelled_at AS reference_cancelled_at,',
|
||||
$paymentSupportsStatus => 'pe.cancelled_at AS reference_cancelled_at,',
|
||||
default => 'NULL AS reference_cancelled_at,',
|
||||
};
|
||||
|
||||
$referenceStatusSql = $coffeeSupportsStatus || $paymentSupportsStatus
|
||||
? <<<'SQL'
|
||||
CASE
|
||||
WHEN le.reference_type = 'coffee_entry' THEN COALESCE(ce.status, 'booked')
|
||||
@@ -3300,7 +3474,7 @@ SQL
|
||||
|
||||
$sql = str_replace(
|
||||
['__COFFEE_STATUS__', '__COFFEE_CANCELLED__', '__PAYMENT_STATUS__', '__REFERENCE_STATUS__', '__REFERENCE_CANCELLED_AT__'],
|
||||
[$coffeeStatusSelect, $coffeeCancelledSelect, $paymentStatusSelect, $referenceStatusSql, 'COALESCE(coffee_reference_cancelled_at, payment_cancelled_at) AS reference_cancelled_at,'],
|
||||
[$coffeeStatusSelect, $coffeeCancelledSelect, $paymentStatusSelect, $referenceStatusSql, $referenceCancelledAtSql],
|
||||
<<<'SQL'
|
||||
SELECT
|
||||
le.id,
|
||||
@@ -3331,8 +3505,8 @@ SQL
|
||||
function app_payments_for_tenant(PDO $pdo, string $tenantId): array
|
||||
{
|
||||
$paymentStatusSelect = app_finance_entries_support_status($pdo, 'payment_entries')
|
||||
? 'pe.status, pe.cancelled_at, pe.cancellation_reason,'
|
||||
: "'booked' AS status, NULL AS cancelled_at, NULL AS cancellation_reason,";
|
||||
? 'pe.status, pe.cancelled_at, pe.cancellation_reason'
|
||||
: "'booked' AS status, NULL AS cancelled_at, NULL AS cancellation_reason";
|
||||
|
||||
$sql = str_replace(
|
||||
'__PAYMENT_STATUS__',
|
||||
|
||||
@@ -362,6 +362,21 @@ if ($auth !== null && $pdo instanceof PDO) {
|
||||
? (string) ($_GET['scope'] ?? 'all')
|
||||
: 'all';
|
||||
$ledgerMembers = app_members_for_scope($pdo, (string) $auth['tenant_id'], $ledgerScope);
|
||||
if ($ledgerMembers === [] && $members !== []) {
|
||||
$ledgerMembers = array_map(
|
||||
static function (array $member): array {
|
||||
$member['recent_strokes'] = (int) ($member['recent_strokes'] ?? 0);
|
||||
return $member;
|
||||
},
|
||||
array_values(array_filter(
|
||||
$members,
|
||||
static function (array $member): bool {
|
||||
$status = strtolower(trim((string) ($member['status'] ?? 'active')));
|
||||
return !in_array($status, ['inactive', 'disabled', 'archived'], true);
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($page === 'payments') {
|
||||
@@ -369,6 +384,21 @@ if ($auth !== null && $pdo instanceof PDO) {
|
||||
? (string) ($_GET['scope'] ?? 'all')
|
||||
: 'all';
|
||||
$paymentMembers = app_members_for_scope($pdo, (string) $auth['tenant_id'], $paymentScope);
|
||||
if ($paymentMembers === [] && $members !== []) {
|
||||
$paymentMembers = array_map(
|
||||
static function (array $member): array {
|
||||
$member['recent_strokes'] = (int) ($member['recent_strokes'] ?? 0);
|
||||
return $member;
|
||||
},
|
||||
array_values(array_filter(
|
||||
$members,
|
||||
static function (array $member): bool {
|
||||
$status = strtolower(trim((string) ($member['status'] ?? 'active')));
|
||||
return !in_array($status, ['inactive', 'disabled', 'archived'], true);
|
||||
}
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($page === 'content' || $page === 'dashboard') {
|
||||
@@ -1505,7 +1535,7 @@ $marketing = app_marketing_messages();
|
||||
</div>
|
||||
<form method="post" action="/ledger/" class="stack">
|
||||
<input type="hidden" name="action" value="bulk-record-coffee">
|
||||
<input type="hidden" name="scope" value="<?= h((string) ($_GET['scope'] ?? 'all')) ?>">
|
||||
<input type="hidden" name="scope" value="<?= h($ledgerScope) ?>">
|
||||
<div class="grid">
|
||||
<label>Preis pro Strich<input type="number" name="unit_price" min="0.01" step="0.01" value="<?= h((string) ($tenantSettings['default_unit_price'] ?? '0.50')) ?>"></label>
|
||||
<label>Buchungszeit<input type="datetime-local" name="booked_at" value="<?= date('Y-m-d\TH:i') ?>"></label>
|
||||
@@ -1560,7 +1590,7 @@ $marketing = app_marketing_messages();
|
||||
</div>
|
||||
<form method="post" action="/payments/" class="stack">
|
||||
<input type="hidden" name="action" value="bulk-record-payment">
|
||||
<input type="hidden" name="scope" value="<?= h((string) ($_GET['scope'] ?? 'all')) ?>">
|
||||
<input type="hidden" name="scope" value="<?= h($paymentScope) ?>">
|
||||
<div class="grid">
|
||||
<label>Zahlungsart<select name="payment_method"><option value="manual">Manuell</option><option value="paypal">PayPal</option><option value="bank">Bank</option></select></label>
|
||||
<label>Buchungszeit<input type="datetime-local" name="booked_at" value="<?= date('Y-m-d\TH:i') ?>"></label>
|
||||
|
||||
Reference in New Issue
Block a user