opencrm/backend/src/services/contractTask.service.ts

312 lines
7.5 KiB
TypeScript

import { ContractTaskStatus } from '@prisma/client';
import prisma from '../lib/prisma.js';
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: { createdAt: 'asc' },
},
},
orderBy: { 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: { 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: { 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 };
}