Compare commits
2 Commits
38651037bc
...
5c28fbdea5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c28fbdea5 | ||
|
|
90ec351d96 |
@@ -20,12 +20,7 @@ interface TableStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IntegrityData {
|
interface IntegrityData {
|
||||||
tables: {
|
tables: Record<string, TableStatus>;
|
||||||
profiles: TableStatus;
|
|
||||||
end_customers: TableStatus;
|
|
||||||
pos_modules: TableStatus;
|
|
||||||
licenses: TableStatus;
|
|
||||||
};
|
|
||||||
errors: {
|
errors: {
|
||||||
foreign_keys: number;
|
foreign_keys: number;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ function toggleModuleInList(
|
|||||||
const beforeLength = next.length
|
const beforeLength = next.length
|
||||||
next = next.filter(mId => {
|
next = next.filter(mId => {
|
||||||
const m = modules.find(mod => mod.id === mId)
|
const m = modules.find(mod => mod.id === mId)
|
||||||
return !m?.requirements || m.requirements.every(reqId => next.includes(reqId))
|
return !m?.requirements || m.requirements.length === 0 || m.requirements.some(reqId => next.includes(reqId))
|
||||||
})
|
})
|
||||||
changed = next.length !== beforeLength
|
changed = next.length !== beforeLength
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ function toggleModuleInList(
|
|||||||
|
|
||||||
function isModuleDisabled(module: ProductModule, selectedModules: string[]): boolean {
|
function isModuleDisabled(module: ProductModule, selectedModules: string[]): boolean {
|
||||||
const requirementsMet = !module.requirements?.length ||
|
const requirementsMet = !module.requirements?.length ||
|
||||||
module.requirements.every(reqId => selectedModules.includes(reqId))
|
module.requirements.some(reqId => selectedModules.includes(reqId))
|
||||||
const isExcluded = module.exclusions?.some(exId => selectedModules.includes(exId))
|
const isExcluded = module.exclusions?.some(exId => selectedModules.includes(exId))
|
||||||
return !requirementsMet || !!isExcluded
|
return !requirementsMet || !!isExcluded
|
||||||
}
|
}
|
||||||
@@ -237,12 +237,12 @@ export function OrderWizard({
|
|||||||
|
|
||||||
// Requirements check
|
// Requirements check
|
||||||
if (prod.requirements && prod.requirements.length > 0) {
|
if (prod.requirements && prod.requirements.length > 0) {
|
||||||
const missing = prod.requirements.filter(reqId => !selectedProductIds.includes(reqId))
|
const hasMetRequirement = prod.requirements.some(reqId => selectedProductIds.includes(reqId))
|
||||||
if (missing.length > 0) {
|
if (!hasMetRequirement) {
|
||||||
const names = missing
|
const names = prod.requirements
|
||||||
.map(reqId => products.find(p => p.id === reqId)?.name || reqId)
|
.map(reqId => products.find(p => p.id === reqId)?.name || reqId)
|
||||||
.join(', ')
|
.join(' oder ')
|
||||||
errors.push(`"${prod.name}" benötigt das Produkt: ${names}`)
|
errors.push(`"${prod.name}" benötigt mindestens eines dieser Produkte: ${names}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,8 +898,8 @@ export function OrderWizard({
|
|||||||
)}
|
)}
|
||||||
{disabled && (
|
{disabled && (
|
||||||
<p className="text-[10px] text-destructive mt-1">
|
<p className="text-[10px] text-destructive mt-1">
|
||||||
{module.requirements?.some(
|
{module.requirements?.length && !module.requirements.some(
|
||||||
reqId => !sel?.moduleIds.includes(reqId)
|
reqId => sel?.moduleIds.includes(reqId)
|
||||||
)
|
)
|
||||||
? 'Benötigt weitere Module'
|
? 'Benötigt weitere Module'
|
||||||
: 'Nicht kombinierbar mit aktueller Auswahl'}
|
: 'Nicht kombinierbar mit aktueller Auswahl'}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { createClient } from '@/lib/supabase/server'
|
import { createClient } from '@/lib/supabase/server'
|
||||||
import { verifyAdmin } from '@/lib/actions/auth'
|
import { verifyAdmin } from '@/lib/actions/auth'
|
||||||
|
import { Client } from 'pg'
|
||||||
|
|
||||||
export async function getDatabaseIntegrity() {
|
export async function getDatabaseIntegrity() {
|
||||||
try {
|
try {
|
||||||
@@ -36,12 +37,20 @@ export async function repairDatabaseSchema() {
|
|||||||
export async function optimizeDatabaseIndices() {
|
export async function optimizeDatabaseIndices() {
|
||||||
try {
|
try {
|
||||||
await verifyAdmin()
|
await verifyAdmin()
|
||||||
const supabase = await createClient()
|
|
||||||
const { data, error } = await supabase.rpc('optimize_database_indices')
|
// REINDEX cannot be run inside a transaction block (such as inside a PL/pgSQL function).
|
||||||
if (error) {
|
// Therefore, we connect directly using pg client and execute raw query.
|
||||||
return { success: false, error: error.message }
|
const connectionString = process.env.DATABASE_URL || 'postgresql://postgres:postgres@localhost:54322/postgres';
|
||||||
}
|
const client = new Client({
|
||||||
return { success: true, data }
|
connectionString,
|
||||||
|
connectionTimeoutMillis: 10000,
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.connect();
|
||||||
|
await client.query('REINDEX SCHEMA public;');
|
||||||
|
await client.end();
|
||||||
|
|
||||||
|
return { success: true }
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error("Error in optimizeDatabaseIndices:", err)
|
console.error("Error in optimizeDatabaseIndices:", err)
|
||||||
return { success: false, error: err.message || "Unerwarteter Fehler bei der Indexoptimierung." }
|
return { success: false, error: err.message || "Unerwarteter Fehler bei der Indexoptimierung." }
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ export async function submitOrder(params: {
|
|||||||
}
|
}
|
||||||
// Requirements check
|
// Requirements check
|
||||||
if (mod.requirements && mod.requirements.length > 0) {
|
if (mod.requirements && mod.requirements.length > 0) {
|
||||||
const missing = mod.requirements.filter(reqId => !sel.moduleIds.includes(reqId))
|
const hasMetRequirement = mod.requirements.some(reqId => sel.moduleIds.includes(reqId))
|
||||||
if (missing.length > 0) {
|
if (!hasMetRequirement) {
|
||||||
throw new Error(`Das Modul "${mod.name}" setzt die Aktivierung anderer Module voraus.`)
|
throw new Error(`Das Modul "${mod.name}" setzt die Aktivierung mindestens eines der folgenden Module voraus: ${mod.requirements.join(', ')}.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Exclusions check
|
// Exclusions check
|
||||||
@@ -117,12 +117,12 @@ export async function submitOrder(params: {
|
|||||||
|
|
||||||
// Product requirements check
|
// Product requirements check
|
||||||
if (prod.requirements && prod.requirements.length > 0) {
|
if (prod.requirements && prod.requirements.length > 0) {
|
||||||
const missing = prod.requirements.filter(reqId => !selectedProductIds.includes(reqId))
|
const hasMetRequirement = prod.requirements.some(reqId => selectedProductIds.includes(reqId))
|
||||||
if (missing.length > 0) {
|
if (!hasMetRequirement) {
|
||||||
const missingNames = missing
|
const reqNames = prod.requirements
|
||||||
.map(reqId => dbProducts.find(p => p.id === reqId)?.name || reqId)
|
.map(reqId => dbProducts.find(p => p.id === reqId)?.name || reqId)
|
||||||
.join(', ')
|
.join(' oder ')
|
||||||
throw new Error(`Das Produkt "${prod.name}" erfordert die Auswahl von: ${missingNames}.`)
|
throw new Error(`Das Produkt "${prod.name}" erfordert die Auswahl von mindestens einem dieser Produkte: ${reqNames}.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,9 +530,9 @@ export async function updateOrder(
|
|||||||
}
|
}
|
||||||
// Requirements check
|
// Requirements check
|
||||||
if (mod.requirements && mod.requirements.length > 0) {
|
if (mod.requirements && mod.requirements.length > 0) {
|
||||||
const missing = mod.requirements.filter(reqId => !sel.moduleIds.includes(reqId))
|
const hasMetRequirement = mod.requirements.some(reqId => sel.moduleIds.includes(reqId))
|
||||||
if (missing.length > 0) {
|
if (!hasMetRequirement) {
|
||||||
throw new Error(`Das Modul "${mod.name}" setzt die Aktivierung anderer Module voraus.`)
|
throw new Error(`Das Modul "${mod.name}" setzt die Aktivierung mindestens eines der folgenden Module voraus: ${mod.requirements.join(', ')}.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Exclusions check
|
// Exclusions check
|
||||||
@@ -557,12 +557,12 @@ export async function updateOrder(
|
|||||||
|
|
||||||
// Product requirements check
|
// Product requirements check
|
||||||
if (prod.requirements && prod.requirements.length > 0) {
|
if (prod.requirements && prod.requirements.length > 0) {
|
||||||
const missing = prod.requirements.filter(reqId => !selectedProductIds.includes(reqId))
|
const hasMetRequirement = prod.requirements.some(reqId => selectedProductIds.includes(reqId))
|
||||||
if (missing.length > 0) {
|
if (!hasMetRequirement) {
|
||||||
const missingNames = missing
|
const reqNames = prod.requirements
|
||||||
.map(reqId => dbProducts.find(p => p.id === reqId)?.name || reqId)
|
.map(reqId => dbProducts.find(p => p.id === reqId)?.name || reqId)
|
||||||
.join(', ')
|
.join(' oder ')
|
||||||
throw new Error(`Das Produkt "${prod.name}" erfordert die Auswahl von: ${missingNames}.`)
|
throw new Error(`Das Produkt "${prod.name}" erfordert die Auswahl von mindestens einem dieser Produkte: ${reqNames}.`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
-- Update check_database_integrity to check all tables
|
||||||
|
CREATE OR REPLACE FUNCTION public.check_database_integrity()
|
||||||
|
RETURNS jsonb
|
||||||
|
SECURITY DEFINER
|
||||||
|
AS $$
|
||||||
|
DECLARE
|
||||||
|
tables_to_check text[] := ARRAY[
|
||||||
|
'users',
|
||||||
|
'settings',
|
||||||
|
'companies',
|
||||||
|
'categories',
|
||||||
|
'products',
|
||||||
|
'product_modules',
|
||||||
|
'orders',
|
||||||
|
'profiles',
|
||||||
|
'end_customers',
|
||||||
|
'licenses',
|
||||||
|
'pos_modules'
|
||||||
|
];
|
||||||
|
t text;
|
||||||
|
t_exists boolean;
|
||||||
|
t_count bigint;
|
||||||
|
tables_result jsonb := jsonb_build_object();
|
||||||
|
fk_errors_count bigint := 0;
|
||||||
|
result jsonb;
|
||||||
|
BEGIN
|
||||||
|
FOREACH t IN ARRAY tables_to_check LOOP
|
||||||
|
SELECT EXISTS (
|
||||||
|
SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = t
|
||||||
|
) INTO t_exists;
|
||||||
|
|
||||||
|
t_count := 0;
|
||||||
|
IF t_exists THEN
|
||||||
|
EXECUTE format('SELECT count(*) FROM public.%I', t) INTO t_count;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
tables_result := tables_result || jsonb_build_object(t, jsonb_build_object('exists', t_exists, 'count', t_count));
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
-- Count foreign key errors (orphaned licenses)
|
||||||
|
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'licenses') INTO t_exists;
|
||||||
|
IF t_exists THEN
|
||||||
|
SELECT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') INTO t_exists;
|
||||||
|
IF t_exists THEN
|
||||||
|
EXECUTE '
|
||||||
|
SELECT count(*)
|
||||||
|
FROM public.licenses l
|
||||||
|
LEFT JOIN public.end_customers c ON l.end_customer_id = c.id
|
||||||
|
WHERE c.id IS NULL AND l.end_customer_id IS NOT NULL
|
||||||
|
' INTO fk_errors_count;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
result := jsonb_build_object(
|
||||||
|
'tables', tables_result,
|
||||||
|
'errors', jsonb_build_object(
|
||||||
|
'foreign_keys', fk_errors_count
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
RETURN result;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
Reference in New Issue
Block a user