first commit
This commit is contained in:
@@ -0,0 +1,324 @@
|
||||
import { PrismaClient, ContractTaskStatus } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export interface ContractTaskFilters {
|
||||
contractId: number;
|
||||
status?: ContractTaskStatus;
|
||||
visibleInPortal?: boolean;
|
||||
// Für Kundenportal: Zeige Tasks die entweder sichtbar sind ODER vom Kunden erstellt wurden
|
||||
customerPortalEmails?: string[];
|
||||
}
|
||||
|
||||
export async function getTasksByContract(filters: ContractTaskFilters) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const where: any = {
|
||||
contractId: filters.contractId,
|
||||
};
|
||||
|
||||
if (filters.status) {
|
||||
where.status = filters.status;
|
||||
}
|
||||
|
||||
// Spezielle Logik für Kundenportal
|
||||
if (filters.customerPortalEmails && filters.customerPortalEmails.length > 0) {
|
||||
// Zeige Tasks die:
|
||||
// 1. visibleInPortal = true ODER
|
||||
// 2. vom Kunden selbst erstellt wurden (createdBy in customerPortalEmails)
|
||||
where.OR = [
|
||||
{ visibleInPortal: true },
|
||||
{ createdBy: { in: filters.customerPortalEmails } },
|
||||
];
|
||||
} else if (filters.visibleInPortal !== undefined) {
|
||||
where.visibleInPortal = filters.visibleInPortal;
|
||||
}
|
||||
|
||||
return prisma.contractTask.findMany({
|
||||
where,
|
||||
include: {
|
||||
subtasks: {
|
||||
orderBy: [
|
||||
{ status: 'asc' },
|
||||
{ createdAt: 'asc' },
|
||||
],
|
||||
},
|
||||
},
|
||||
orderBy: [
|
||||
{ status: 'asc' }, // OPEN first, then COMPLETED
|
||||
{ createdAt: 'desc' },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export async function getTaskById(id: number) {
|
||||
return prisma.contractTask.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export async function createTask(data: {
|
||||
contractId: number;
|
||||
title: string;
|
||||
description?: string;
|
||||
visibleInPortal?: boolean;
|
||||
createdBy?: string;
|
||||
}) {
|
||||
return prisma.contractTask.create({
|
||||
data: {
|
||||
contractId: data.contractId,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
visibleInPortal: data.visibleInPortal ?? false,
|
||||
createdBy: data.createdBy,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateTask(
|
||||
id: number,
|
||||
data: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
visibleInPortal?: boolean;
|
||||
}
|
||||
) {
|
||||
return prisma.contractTask.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export async function completeTask(id: number) {
|
||||
return prisma.contractTask.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: 'COMPLETED',
|
||||
completedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function reopenTask(id: number) {
|
||||
return prisma.contractTask.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: 'OPEN',
|
||||
completedAt: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteTask(id: number) {
|
||||
return prisma.contractTask.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== SUBTASKS ====================
|
||||
|
||||
export async function createSubtask(data: { taskId: number; title: string; createdBy?: string }) {
|
||||
return prisma.contractTaskSubtask.create({
|
||||
data: {
|
||||
taskId: data.taskId,
|
||||
title: data.title,
|
||||
createdBy: data.createdBy,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateSubtask(id: number, data: { title?: string }) {
|
||||
return prisma.contractTaskSubtask.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
export async function completeSubtask(id: number) {
|
||||
// Complete the subtask
|
||||
const subtask = await prisma.contractTaskSubtask.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: 'COMPLETED',
|
||||
completedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// Check if all subtasks of the parent task are now completed
|
||||
const remainingOpenSubtasks = await prisma.contractTaskSubtask.count({
|
||||
where: {
|
||||
taskId: subtask.taskId,
|
||||
status: 'OPEN',
|
||||
},
|
||||
});
|
||||
|
||||
// If no open subtasks remain, automatically complete the parent task
|
||||
if (remainingOpenSubtasks === 0) {
|
||||
await prisma.contractTask.update({
|
||||
where: { id: subtask.taskId },
|
||||
data: {
|
||||
status: 'COMPLETED',
|
||||
completedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return subtask;
|
||||
}
|
||||
|
||||
export async function reopenSubtask(id: number) {
|
||||
// Reopen the subtask
|
||||
const subtask = await prisma.contractTaskSubtask.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: 'OPEN',
|
||||
completedAt: null,
|
||||
},
|
||||
});
|
||||
|
||||
// If the parent task was completed, reopen it as well
|
||||
const parentTask = await prisma.contractTask.findUnique({
|
||||
where: { id: subtask.taskId },
|
||||
});
|
||||
|
||||
if (parentTask?.status === 'COMPLETED') {
|
||||
await prisma.contractTask.update({
|
||||
where: { id: subtask.taskId },
|
||||
data: {
|
||||
status: 'OPEN',
|
||||
completedAt: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return subtask;
|
||||
}
|
||||
|
||||
export async function deleteSubtask(id: number) {
|
||||
return prisma.contractTaskSubtask.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
|
||||
export async function getSubtaskById(id: number) {
|
||||
return prisma.contractTaskSubtask.findUnique({
|
||||
where: { id },
|
||||
include: { task: true },
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== ALL TASKS ====================
|
||||
|
||||
export interface AllTasksFilters {
|
||||
status?: ContractTaskStatus;
|
||||
customerId?: number;
|
||||
// Für Kundenportal: Nur Tasks für erlaubte Verträge und sichtbare/eigene Tasks
|
||||
customerPortalCustomerIds?: number[];
|
||||
customerPortalEmails?: string[];
|
||||
}
|
||||
|
||||
export async function getAllTasks(filters: AllTasksFilters) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const where: any = {};
|
||||
|
||||
if (filters.status) {
|
||||
where.status = filters.status;
|
||||
}
|
||||
|
||||
// Für Kundenportal: Filter auf erlaubte Verträge + Sichtbarkeit
|
||||
if (filters.customerPortalCustomerIds && filters.customerPortalCustomerIds.length > 0) {
|
||||
where.contract = {
|
||||
customerId: { in: filters.customerPortalCustomerIds },
|
||||
};
|
||||
// Zeige nur sichtbare Tasks ODER vom Kunden erstellte
|
||||
if (filters.customerPortalEmails && filters.customerPortalEmails.length > 0) {
|
||||
where.OR = [
|
||||
{ visibleInPortal: true },
|
||||
{ createdBy: { in: filters.customerPortalEmails } },
|
||||
];
|
||||
} else {
|
||||
where.visibleInPortal = true;
|
||||
}
|
||||
} else if (filters.customerId) {
|
||||
// Für Mitarbeiter: Optional nach Kunde filtern
|
||||
where.contract = {
|
||||
customerId: filters.customerId,
|
||||
};
|
||||
}
|
||||
|
||||
return prisma.contractTask.findMany({
|
||||
where,
|
||||
include: {
|
||||
subtasks: {
|
||||
orderBy: [
|
||||
{ status: 'asc' },
|
||||
{ createdAt: 'asc' },
|
||||
],
|
||||
},
|
||||
contract: {
|
||||
select: {
|
||||
id: true,
|
||||
contractNumber: true,
|
||||
customerId: true,
|
||||
customer: {
|
||||
select: {
|
||||
id: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
customerNumber: true,
|
||||
},
|
||||
},
|
||||
provider: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
tariff: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
providerName: true,
|
||||
tariffName: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: [
|
||||
{ status: 'asc' }, // OPEN first, then COMPLETED
|
||||
{ createdAt: 'desc' },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export async function getTaskStats(filters: AllTasksFilters) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const where: any = {
|
||||
status: 'OPEN',
|
||||
};
|
||||
|
||||
// Für Kundenportal: Filter auf erlaubte Verträge + Sichtbarkeit
|
||||
if (filters.customerPortalCustomerIds && filters.customerPortalCustomerIds.length > 0) {
|
||||
where.contract = {
|
||||
customerId: { in: filters.customerPortalCustomerIds },
|
||||
};
|
||||
// Zeige nur sichtbare Tasks ODER vom Kunden erstellte
|
||||
if (filters.customerPortalEmails && filters.customerPortalEmails.length > 0) {
|
||||
where.OR = [
|
||||
{ visibleInPortal: true },
|
||||
{ createdBy: { in: filters.customerPortalEmails } },
|
||||
];
|
||||
} else {
|
||||
where.visibleInPortal = true;
|
||||
}
|
||||
} else if (filters.customerId) {
|
||||
where.contract = {
|
||||
customerId: filters.customerId,
|
||||
};
|
||||
}
|
||||
|
||||
const openCount = await prisma.contractTask.count({ where });
|
||||
|
||||
return { openCount };
|
||||
}
|
||||
Reference in New Issue
Block a user