first commit
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
export declare function getSetting(key: string): Promise<string | null>;
|
||||
export declare function getSettingBool(key: string): Promise<boolean>;
|
||||
export declare function setSetting(key: string, value: string): Promise<void>;
|
||||
export declare function getAllSettings(): Promise<Record<string, string>>;
|
||||
export declare function getPublicSettings(): Promise<Record<string, string>>;
|
||||
//# sourceMappingURL=appSetting.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"appSetting.service.d.ts","sourceRoot":"","sources":["../../src/services/appSetting.service.ts"],"names":[],"mappings":"AAaA,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWpE;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAGlE;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1E;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAWtE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAazE"}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getSetting = getSetting;
|
||||
exports.getSettingBool = getSettingBool;
|
||||
exports.setSetting = setSetting;
|
||||
exports.getAllSettings = getAllSettings;
|
||||
exports.getPublicSettings = getPublicSettings;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
// Default settings
|
||||
const DEFAULT_SETTINGS = {
|
||||
customerSupportTicketsEnabled: 'false',
|
||||
// Vertrags-Cockpit: Fristenschwellen (in Tagen)
|
||||
deadlineCriticalDays: '14', // Rot: Kritisch
|
||||
deadlineWarningDays: '42', // Gelb: Warnung (6 Wochen)
|
||||
deadlineOkDays: '90', // Grün: OK (3 Monate)
|
||||
};
|
||||
async function getSetting(key) {
|
||||
const setting = await prisma.appSetting.findUnique({
|
||||
where: { key },
|
||||
});
|
||||
if (setting) {
|
||||
return setting.value;
|
||||
}
|
||||
// Return default if exists
|
||||
return DEFAULT_SETTINGS[key] ?? null;
|
||||
}
|
||||
async function getSettingBool(key) {
|
||||
const value = await getSetting(key);
|
||||
return value === 'true';
|
||||
}
|
||||
async function setSetting(key, value) {
|
||||
await prisma.appSetting.upsert({
|
||||
where: { key },
|
||||
update: { value },
|
||||
create: { key, value },
|
||||
});
|
||||
}
|
||||
async function getAllSettings() {
|
||||
const settings = await prisma.appSetting.findMany();
|
||||
// Start with defaults, then override with stored values
|
||||
const result = { ...DEFAULT_SETTINGS };
|
||||
for (const setting of settings) {
|
||||
result[setting.key] = setting.value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
async function getPublicSettings() {
|
||||
// Settings that should be available to all authenticated users (including customers)
|
||||
const publicKeys = ['customerSupportTicketsEnabled'];
|
||||
const allSettings = await getAllSettings();
|
||||
const result = {};
|
||||
for (const key of publicKeys) {
|
||||
if (key in allSettings) {
|
||||
result[key] = allSettings[key];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//# sourceMappingURL=appSetting.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"appSetting.service.js","sourceRoot":"","sources":["../../src/services/appSetting.service.ts"],"names":[],"mappings":";;AAaA,gCAWC;AAED,wCAGC;AAED,gCAMC;AAED,wCAWC;AAED,8CAaC;AAjED,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAElC,mBAAmB;AACnB,MAAM,gBAAgB,GAA2B;IAC/C,6BAA6B,EAAE,OAAO;IACtC,gDAAgD;IAChD,oBAAoB,EAAE,IAAI,EAAO,gBAAgB;IACjD,mBAAmB,EAAE,IAAI,EAAQ,2BAA2B;IAC5D,cAAc,EAAE,IAAI,EAAa,sBAAsB;CACxD,CAAC;AAEK,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC;QACjD,KAAK,EAAE,EAAE,GAAG,EAAE;KACf,CAAC,CAAC;IAEH,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC,KAAK,CAAC;IACvB,CAAC;IAED,2BAA2B;IAC3B,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;AACvC,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,GAAW;IAC9C,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,KAAK,KAAK,MAAM,CAAC;AAC1B,CAAC;AAEM,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,KAAa;IACzD,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAC7B,KAAK,EAAE,EAAE,GAAG,EAAE;QACd,MAAM,EAAE,EAAE,KAAK,EAAE;QACjB,MAAM,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE;KACvB,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc;IAClC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IAEpD,wDAAwD;IACxD,MAAM,MAAM,GAAG,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAEvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;IACtC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAEM,KAAK,UAAU,iBAAiB;IACrC,qFAAqF;IACrF,MAAM,UAAU,GAAG,CAAC,+BAA+B,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAE3C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
export declare function login(email: string, password: string): Promise<{
|
||||
token: string;
|
||||
user: {
|
||||
id: number;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
permissions: string[];
|
||||
customerId: number | null;
|
||||
isCustomerPortal: boolean;
|
||||
};
|
||||
}>;
|
||||
export declare function customerLogin(email: string, password: string): Promise<{
|
||||
token: string;
|
||||
user: {
|
||||
id: number;
|
||||
email: string | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
permissions: string[];
|
||||
customerId: number;
|
||||
isCustomerPortal: boolean;
|
||||
representedCustomers: {
|
||||
id: number;
|
||||
customerNumber: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
companyName: string | null;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
}[];
|
||||
};
|
||||
}>;
|
||||
export declare function setCustomerPortalPassword(customerId: number, password: string): Promise<void>;
|
||||
export declare function getCustomerPortalPassword(customerId: number): Promise<string | null>;
|
||||
export declare function createUser(data: {
|
||||
email: string;
|
||||
password: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
roleIds: number[];
|
||||
customerId?: number;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
roles: string[];
|
||||
}>;
|
||||
export declare function getUserById(id: number): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
isActive: boolean;
|
||||
customerId: number | null;
|
||||
roles: string[];
|
||||
permissions: string[];
|
||||
isCustomerPortal: boolean;
|
||||
} | null>;
|
||||
export declare function getCustomerPortalUser(customerId: number): Promise<{
|
||||
id: number;
|
||||
email: string | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
isActive: true;
|
||||
customerId: number;
|
||||
permissions: string[];
|
||||
isCustomerPortal: boolean;
|
||||
representedCustomers: {
|
||||
id: number;
|
||||
customerNumber: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
companyName: string | null;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
}[];
|
||||
} | null>;
|
||||
//# sourceMappingURL=auth.service.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.service.d.ts","sourceRoot":"","sources":["../../src/services/auth.service.ts"],"names":[],"mappings":"AASA,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;;;;GA+D1D;AAGD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;;;;;;;;;;;;;;;;;;;GAwFlE;AAGD,wBAAsB,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,iBAiBnF;AAGD,wBAAsB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgB1F;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;;;;;;GA8BA;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;UA8C3C;AAGD,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM;;;;;;;;;;;;;;;;;UA+C7D"}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.login = login;
|
||||
exports.customerLogin = customerLogin;
|
||||
exports.setCustomerPortalPassword = setCustomerPortalPassword;
|
||||
exports.getCustomerPortalPassword = getCustomerPortalPassword;
|
||||
exports.createUser = createUser;
|
||||
exports.getUserById = getUserById;
|
||||
exports.getCustomerPortalUser = getCustomerPortalUser;
|
||||
const client_1 = require("@prisma/client");
|
||||
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
||||
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
||||
const encryption_js_1 = require("../utils/encryption.js");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
// Mitarbeiter-Login
|
||||
async function login(email, password) {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { email },
|
||||
include: {
|
||||
roles: {
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: {
|
||||
include: {
|
||||
permission: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!user || !user.isActive) {
|
||||
throw new Error('Ungültige Anmeldedaten');
|
||||
}
|
||||
const isValid = await bcryptjs_1.default.compare(password, user.password);
|
||||
if (!isValid) {
|
||||
throw new Error('Ungültige Anmeldedaten');
|
||||
}
|
||||
// Collect all permissions from all roles
|
||||
const permissions = new Set();
|
||||
for (const userRole of user.roles) {
|
||||
for (const rolePerm of userRole.role.permissions) {
|
||||
permissions.add(`${rolePerm.permission.resource}:${rolePerm.permission.action}`);
|
||||
}
|
||||
}
|
||||
const payload = {
|
||||
userId: user.id,
|
||||
email: user.email,
|
||||
permissions: Array.from(permissions),
|
||||
customerId: user.customerId ?? undefined,
|
||||
isCustomerPortal: false,
|
||||
};
|
||||
const token = jsonwebtoken_1.default.sign(payload, process.env.JWT_SECRET || 'fallback-secret', {
|
||||
expiresIn: (process.env.JWT_EXPIRES_IN || '7d'),
|
||||
});
|
||||
return {
|
||||
token,
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
permissions: Array.from(permissions),
|
||||
customerId: user.customerId,
|
||||
isCustomerPortal: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
// Kundenportal-Login
|
||||
async function customerLogin(email, password) {
|
||||
console.log('[CustomerLogin] Versuch mit E-Mail:', email);
|
||||
const customer = await prisma.customer.findUnique({
|
||||
where: { portalEmail: email },
|
||||
include: {
|
||||
// Kunden, die dieser Kunde vertreten kann
|
||||
representingFor: {
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
customer: {
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log('[CustomerLogin] Kunde gefunden:', customer ? `ID ${customer.id}, portalEnabled: ${customer.portalEnabled}, hasPasswordHash: ${!!customer.portalPasswordHash}` : 'NEIN');
|
||||
if (!customer || !customer.portalEnabled || !customer.portalPasswordHash) {
|
||||
console.log('[CustomerLogin] Abbruch: Kunde nicht gefunden oder Portal nicht aktiviert');
|
||||
throw new Error('Ungültige Anmeldedaten');
|
||||
}
|
||||
const isValid = await bcryptjs_1.default.compare(password, customer.portalPasswordHash);
|
||||
console.log('[CustomerLogin] Passwort-Check:', isValid ? 'OK' : 'FALSCH');
|
||||
if (!isValid) {
|
||||
throw new Error('Ungültige Anmeldedaten');
|
||||
}
|
||||
// Letzte Anmeldung aktualisieren
|
||||
await prisma.customer.update({
|
||||
where: { id: customer.id },
|
||||
data: { portalLastLogin: new Date() },
|
||||
});
|
||||
// IDs der Kunden sammeln, die dieser Kunde vertreten kann
|
||||
const representedCustomerIds = customer.representingFor.map((rep) => rep.customer.id);
|
||||
// Kundenportal-Berechtigungen (eingeschränkt)
|
||||
const customerPermissions = [
|
||||
'contracts:read', // Eigene Verträge lesen
|
||||
'customers:read', // Eigene Kundendaten lesen
|
||||
];
|
||||
const payload = {
|
||||
email: customer.portalEmail,
|
||||
permissions: customerPermissions,
|
||||
customerId: customer.id,
|
||||
isCustomerPortal: true,
|
||||
representedCustomerIds,
|
||||
};
|
||||
const token = jsonwebtoken_1.default.sign(payload, process.env.JWT_SECRET || 'fallback-secret', {
|
||||
expiresIn: (process.env.JWT_EXPIRES_IN || '7d'),
|
||||
});
|
||||
return {
|
||||
token,
|
||||
user: {
|
||||
id: customer.id,
|
||||
email: customer.portalEmail,
|
||||
firstName: customer.firstName,
|
||||
lastName: customer.lastName,
|
||||
permissions: customerPermissions,
|
||||
customerId: customer.id,
|
||||
isCustomerPortal: true,
|
||||
representedCustomers: customer.representingFor.map((rep) => ({
|
||||
id: rep.customer.id,
|
||||
customerNumber: rep.customer.customerNumber,
|
||||
firstName: rep.customer.firstName,
|
||||
lastName: rep.customer.lastName,
|
||||
companyName: rep.customer.companyName,
|
||||
type: rep.customer.type,
|
||||
})),
|
||||
},
|
||||
};
|
||||
}
|
||||
// Kundenportal-Passwort setzen/ändern
|
||||
async function setCustomerPortalPassword(customerId, password) {
|
||||
console.log('[SetPortalPassword] Setze Passwort für Kunde:', customerId);
|
||||
const hashedPassword = await bcryptjs_1.default.hash(password, 10);
|
||||
const encryptedPassword = (0, encryption_js_1.encrypt)(password);
|
||||
console.log('[SetPortalPassword] Hash erstellt, Länge:', hashedPassword.length);
|
||||
await prisma.customer.update({
|
||||
where: { id: customerId },
|
||||
data: {
|
||||
portalPasswordHash: hashedPassword,
|
||||
portalPasswordEncrypted: encryptedPassword,
|
||||
},
|
||||
});
|
||||
console.log('[SetPortalPassword] Passwort gespeichert');
|
||||
}
|
||||
// Kundenportal-Passwort im Klartext abrufen
|
||||
async function getCustomerPortalPassword(customerId) {
|
||||
const customer = await prisma.customer.findUnique({
|
||||
where: { id: customerId },
|
||||
select: { portalPasswordEncrypted: true },
|
||||
});
|
||||
if (!customer?.portalPasswordEncrypted) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (0, encryption_js_1.decrypt)(customer.portalPasswordEncrypted);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Fehler beim Entschlüsseln des Passworts:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async function createUser(data) {
|
||||
const hashedPassword = await bcryptjs_1.default.hash(data.password, 10);
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
email: data.email,
|
||||
password: hashedPassword,
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
customerId: data.customerId,
|
||||
roles: {
|
||||
create: data.roleIds.map((roleId) => ({ roleId })),
|
||||
},
|
||||
},
|
||||
include: {
|
||||
roles: {
|
||||
include: {
|
||||
role: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
roles: user.roles.map((ur) => ur.role.name),
|
||||
};
|
||||
}
|
||||
async function getUserById(id) {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
roles: {
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: {
|
||||
include: {
|
||||
permission: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!user)
|
||||
return null;
|
||||
console.log('auth.getUserById - user roles:', user.roles.map(ur => ur.role.name));
|
||||
const permissions = new Set();
|
||||
for (const userRole of user.roles) {
|
||||
for (const rolePerm of userRole.role.permissions) {
|
||||
permissions.add(`${rolePerm.permission.resource}:${rolePerm.permission.action}`);
|
||||
}
|
||||
}
|
||||
console.log('auth.getUserById - permissions:', Array.from(permissions));
|
||||
return {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
firstName: user.firstName,
|
||||
lastName: user.lastName,
|
||||
isActive: user.isActive,
|
||||
customerId: user.customerId,
|
||||
roles: user.roles.map((ur) => ur.role.name),
|
||||
permissions: Array.from(permissions),
|
||||
isCustomerPortal: false,
|
||||
};
|
||||
}
|
||||
// Kundenportal-Benutzer laden (für /me Endpoint)
|
||||
async function getCustomerPortalUser(customerId) {
|
||||
const customer = await prisma.customer.findUnique({
|
||||
where: { id: customerId },
|
||||
include: {
|
||||
representingFor: {
|
||||
where: { isActive: true },
|
||||
include: {
|
||||
customer: {
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!customer || !customer.portalEnabled)
|
||||
return null;
|
||||
const customerPermissions = [
|
||||
'contracts:read',
|
||||
'customers:read',
|
||||
];
|
||||
return {
|
||||
id: customer.id,
|
||||
email: customer.portalEmail,
|
||||
firstName: customer.firstName,
|
||||
lastName: customer.lastName,
|
||||
isActive: customer.portalEnabled,
|
||||
customerId: customer.id,
|
||||
permissions: customerPermissions,
|
||||
isCustomerPortal: true,
|
||||
representedCustomers: customer.representingFor.map((rep) => ({
|
||||
id: rep.customer.id,
|
||||
customerNumber: rep.customer.customerNumber,
|
||||
firstName: rep.customer.firstName,
|
||||
lastName: rep.customer.lastName,
|
||||
companyName: rep.customer.companyName,
|
||||
type: rep.customer.type,
|
||||
})),
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=auth.service.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,52 @@
|
||||
export declare function getAllCancellationPeriods(includeInactive?: boolean): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}[]>;
|
||||
export declare function getCancellationPeriodById(id: number): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}) | null>;
|
||||
export declare function createCancellationPeriod(data: {
|
||||
code: string;
|
||||
description: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}>;
|
||||
export declare function updateCancellationPeriod(id: number, data: {
|
||||
code?: string;
|
||||
description?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}>;
|
||||
export declare function deleteCancellationPeriod(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}>;
|
||||
//# sourceMappingURL=cancellation-period.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"cancellation-period.service.d.ts","sourceRoot":"","sources":["../../src/services/cancellation-period.service.ts"],"names":[],"mappings":"AAIA,wBAAsB,yBAAyB,CAAC,eAAe,UAAQ;;;;;;;KAMtE;AAED,wBAAsB,yBAAyB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;WASzD;AAED,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;;;;;;;GAOA;AAED,wBAAsB,wBAAwB,CAC5C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;GAMF;AAED,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,MAAM;;;;;;;GAaxD"}
|
||||
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllCancellationPeriods = getAllCancellationPeriods;
|
||||
exports.getCancellationPeriodById = getCancellationPeriodById;
|
||||
exports.createCancellationPeriod = createCancellationPeriod;
|
||||
exports.updateCancellationPeriod = updateCancellationPeriod;
|
||||
exports.deleteCancellationPeriod = deleteCancellationPeriod;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getAllCancellationPeriods(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
return prisma.cancellationPeriod.findMany({
|
||||
where,
|
||||
orderBy: { code: 'asc' },
|
||||
});
|
||||
}
|
||||
async function getCancellationPeriodById(id) {
|
||||
return prisma.cancellationPeriod.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function createCancellationPeriod(data) {
|
||||
return prisma.cancellationPeriod.create({
|
||||
data: {
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateCancellationPeriod(id, data) {
|
||||
return prisma.cancellationPeriod.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteCancellationPeriod(id) {
|
||||
// Check if cancellation period is used by any contracts
|
||||
const count = await prisma.contract.count({
|
||||
where: { cancellationPeriodId: id },
|
||||
});
|
||||
if (count > 0) {
|
||||
throw new Error(`Kündigungsfrist kann nicht gelöscht werden, da sie von ${count} Verträgen verwendet wird`);
|
||||
}
|
||||
return prisma.cancellationPeriod.delete({ where: { id } });
|
||||
}
|
||||
//# sourceMappingURL=cancellation-period.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"cancellation-period.service.js","sourceRoot":"","sources":["../../src/services/cancellation-period.service.ts"],"names":[],"mappings":";;AAIA,8DAMC;AAED,8DASC;AAED,4DAUC;AAED,4DAYC;AAED,4DAaC;AA9DD,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAE3B,KAAK,UAAU,yBAAyB,CAAC,eAAe,GAAG,KAAK;IACrE,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxD,OAAO,MAAM,CAAC,kBAAkB,CAAC,QAAQ,CAAC;QACxC,KAAK;QACL,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;KACzB,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,yBAAyB,CAAC,EAAU;IACxD,OAAO,MAAM,CAAC,kBAAkB,CAAC,UAAU,CAAC;QAC1C,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,wBAAwB,CAAC,IAG9C;IACC,OAAO,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC;QACtC,IAAI,EAAE;YACJ,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,wBAAwB,CAC5C,EAAU,EACV,IAIC;IAED,OAAO,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC;QACtC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,wBAAwB,CAAC,EAAU;IACvD,wDAAwD;IACxD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxC,KAAK,EAAE,EAAE,oBAAoB,EAAE,EAAE,EAAE;KACpC,CAAC,CAAC;IAEH,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,0DAA0D,KAAK,2BAA2B,CAC3F,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC"}
|
||||
@@ -0,0 +1,52 @@
|
||||
export declare function getAllContractDurations(includeInactive?: boolean): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}[]>;
|
||||
export declare function getContractDurationById(id: number): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}) | null>;
|
||||
export declare function createContractDuration(data: {
|
||||
code: string;
|
||||
description: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}>;
|
||||
export declare function updateContractDuration(id: number, data: {
|
||||
code?: string;
|
||||
description?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}>;
|
||||
export declare function deleteContractDuration(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string;
|
||||
code: string;
|
||||
}>;
|
||||
//# sourceMappingURL=contract-duration.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"contract-duration.service.d.ts","sourceRoot":"","sources":["../../src/services/contract-duration.service.ts"],"names":[],"mappings":"AAIA,wBAAsB,uBAAuB,CAAC,eAAe,UAAQ;;;;;;;KAMpE;AAED,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;WASvD;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;;;;;;;GAOA;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;GAMF;AAED,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM;;;;;;;GAatD"}
|
||||
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllContractDurations = getAllContractDurations;
|
||||
exports.getContractDurationById = getContractDurationById;
|
||||
exports.createContractDuration = createContractDuration;
|
||||
exports.updateContractDuration = updateContractDuration;
|
||||
exports.deleteContractDuration = deleteContractDuration;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getAllContractDurations(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
return prisma.contractDuration.findMany({
|
||||
where,
|
||||
orderBy: { code: 'asc' },
|
||||
});
|
||||
}
|
||||
async function getContractDurationById(id) {
|
||||
return prisma.contractDuration.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function createContractDuration(data) {
|
||||
return prisma.contractDuration.create({
|
||||
data: {
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateContractDuration(id, data) {
|
||||
return prisma.contractDuration.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteContractDuration(id) {
|
||||
// Check if contract duration is used by any contracts
|
||||
const count = await prisma.contract.count({
|
||||
where: { contractDurationId: id },
|
||||
});
|
||||
if (count > 0) {
|
||||
throw new Error(`Laufzeit kann nicht gelöscht werden, da sie von ${count} Verträgen verwendet wird`);
|
||||
}
|
||||
return prisma.contractDuration.delete({ where: { id } });
|
||||
}
|
||||
//# sourceMappingURL=contract-duration.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"contract-duration.service.js","sourceRoot":"","sources":["../../src/services/contract-duration.service.ts"],"names":[],"mappings":";;AAIA,0DAMC;AAED,0DASC;AAED,wDAUC;AAED,wDAYC;AAED,wDAaC;AA9DD,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAE3B,KAAK,UAAU,uBAAuB,CAAC,eAAe,GAAG,KAAK;IACnE,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxD,OAAO,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QACtC,KAAK;QACL,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;KACzB,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,uBAAuB,CAAC,EAAU;IACtD,OAAO,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC;QACxC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAAC,IAG5C;IACC,OAAO,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACpC,IAAI,EAAE;YACJ,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAC1C,EAAU,EACV,IAIC;IAED,OAAO,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACpC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAAC,EAAU;IACrD,sDAAsD;IACtD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxC,KAAK,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE;KAClC,CAAC,CAAC;IAEH,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,mDAAmD,KAAK,2BAA2B,CACpF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC3D,CAAC"}
|
||||
+1464
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+570
@@ -0,0 +1,570 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllContracts = getAllContracts;
|
||||
exports.getContractById = getContractById;
|
||||
exports.createContract = createContract;
|
||||
exports.updateContract = updateContract;
|
||||
exports.deleteContract = deleteContract;
|
||||
exports.createFollowUpContract = createFollowUpContract;
|
||||
exports.getContractPassword = getContractPassword;
|
||||
exports.getSimCardCredentials = getSimCardCredentials;
|
||||
exports.getInternetCredentials = getInternetCredentials;
|
||||
exports.getSipCredentials = getSipCredentials;
|
||||
const client_1 = require("@prisma/client");
|
||||
const helpers_js_1 = require("../utils/helpers.js");
|
||||
const encryption_js_1 = require("../utils/encryption.js");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getAllContracts(filters) {
|
||||
const { customerId, customerIds, type, status, search, page = 1, limit = 20 } = filters;
|
||||
const { skip, take } = (0, helpers_js_1.paginate)(page, limit);
|
||||
const where = {};
|
||||
// Entweder einzelne customerId ODER Liste von customerIds (für Kundenportal)
|
||||
if (customerIds && customerIds.length > 0) {
|
||||
where.customerId = { in: customerIds };
|
||||
}
|
||||
else if (customerId) {
|
||||
where.customerId = customerId;
|
||||
}
|
||||
if (type)
|
||||
where.type = type;
|
||||
if (status)
|
||||
where.status = status;
|
||||
if (search) {
|
||||
where.OR = [
|
||||
// Basis-Vertragsfelder
|
||||
{ contractNumber: { contains: search } },
|
||||
{ providerName: { contains: search } },
|
||||
{ tariffName: { contains: search } },
|
||||
{ customerNumberAtProvider: { contains: search } },
|
||||
{ provider: { name: { contains: search } } },
|
||||
{ tariff: { name: { contains: search } } },
|
||||
// Kundenname
|
||||
{ customer: { firstName: { contains: search } } },
|
||||
{ customer: { lastName: { contains: search } } },
|
||||
{ customer: { companyName: { contains: search } } },
|
||||
{ customer: { customerNumber: { contains: search } } },
|
||||
// Internet-Vertragsdetails
|
||||
{ internetDetails: { routerSerialNumber: { contains: search } } },
|
||||
{ internetDetails: { homeId: { contains: search } } },
|
||||
{ internetDetails: { activationCode: { contains: search } } },
|
||||
{ internetDetails: { phoneNumbers: { some: { phoneNumber: { contains: search } } } } },
|
||||
// Mobilfunk-Vertragsdetails
|
||||
{ mobileDetails: { phoneNumber: { contains: search } } },
|
||||
{ mobileDetails: { simCardNumber: { contains: search } } },
|
||||
{ mobileDetails: { deviceImei: { contains: search } } },
|
||||
{ mobileDetails: { simCards: { some: { phoneNumber: { contains: search } } } } },
|
||||
{ mobileDetails: { simCards: { some: { simCardNumber: { contains: search } } } } },
|
||||
// Energie-Vertragsdetails (Zählernummer)
|
||||
{ energyDetails: { meter: { meterNumber: { contains: search } } } },
|
||||
// TV-Vertragsdetails
|
||||
{ tvDetails: { smartcardNumber: { contains: search } } },
|
||||
// KFZ-Versicherung
|
||||
{ carInsuranceDetails: { licensePlate: { contains: search } } },
|
||||
{ carInsuranceDetails: { vin: { contains: search } } },
|
||||
{ carInsuranceDetails: { policyNumber: { contains: search } } },
|
||||
];
|
||||
}
|
||||
const [contracts, total] = await Promise.all([
|
||||
prisma.contract.findMany({
|
||||
where,
|
||||
skip,
|
||||
take,
|
||||
orderBy: [{ startDate: 'desc' }, { createdAt: 'desc' }],
|
||||
include: {
|
||||
customer: {
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
},
|
||||
},
|
||||
address: true,
|
||||
salesPlatform: true,
|
||||
cancellationPeriod: true,
|
||||
contractDuration: true,
|
||||
provider: true,
|
||||
tariff: true,
|
||||
contractCategory: true,
|
||||
},
|
||||
}),
|
||||
prisma.contract.count({ where }),
|
||||
]);
|
||||
return {
|
||||
contracts,
|
||||
pagination: (0, helpers_js_1.buildPaginationResponse)(page, limit, total),
|
||||
};
|
||||
}
|
||||
async function getContractById(id, decryptPassword = false) {
|
||||
const contract = await prisma.contract.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
customer: true,
|
||||
address: true,
|
||||
bankCard: true,
|
||||
identityDocument: true,
|
||||
salesPlatform: true,
|
||||
cancellationPeriod: true,
|
||||
contractDuration: true,
|
||||
provider: true,
|
||||
tariff: true,
|
||||
contractCategory: true,
|
||||
previousContract: {
|
||||
include: {
|
||||
energyDetails: { include: { meter: { include: { readings: true } } } },
|
||||
internetDetails: { include: { phoneNumbers: true } },
|
||||
mobileDetails: { include: { simCards: true } },
|
||||
tvDetails: true,
|
||||
carInsuranceDetails: true,
|
||||
},
|
||||
},
|
||||
energyDetails: { include: { meter: { include: { readings: true } } } },
|
||||
internetDetails: { include: { phoneNumbers: true } },
|
||||
mobileDetails: { include: { simCards: true } },
|
||||
tvDetails: true,
|
||||
carInsuranceDetails: true,
|
||||
stressfreiEmail: true,
|
||||
},
|
||||
});
|
||||
if (!contract)
|
||||
return null;
|
||||
// Decrypt password if requested and exists
|
||||
if (decryptPassword && contract.portalPasswordEncrypted) {
|
||||
try {
|
||||
contract.portalPasswordDecrypted = (0, encryption_js_1.decrypt)(contract.portalPasswordEncrypted);
|
||||
}
|
||||
catch {
|
||||
// Password decryption failed, leave as is
|
||||
}
|
||||
}
|
||||
return contract;
|
||||
}
|
||||
async function createContract(data) {
|
||||
const { energyDetails, internetDetails, mobileDetails, tvDetails, carInsuranceDetails, portalPassword, ...contractData } = data;
|
||||
// Encrypt password if provided
|
||||
const portalPasswordEncrypted = portalPassword
|
||||
? (0, encryption_js_1.encrypt)(portalPassword)
|
||||
: undefined;
|
||||
const contract = await prisma.contract.create({
|
||||
data: {
|
||||
...contractData,
|
||||
contractNumber: (0, helpers_js_1.generateContractNumber)(data.type),
|
||||
portalPasswordEncrypted,
|
||||
...(energyDetails && ['ELECTRICITY', 'GAS'].includes(data.type)
|
||||
? { energyDetails: { create: energyDetails } }
|
||||
: {}),
|
||||
...(internetDetails && ['DSL', 'CABLE', 'FIBER'].includes(data.type)
|
||||
? {
|
||||
internetDetails: {
|
||||
create: {
|
||||
downloadSpeed: internetDetails.downloadSpeed,
|
||||
uploadSpeed: internetDetails.uploadSpeed,
|
||||
routerModel: internetDetails.routerModel,
|
||||
routerSerialNumber: internetDetails.routerSerialNumber,
|
||||
installationDate: internetDetails.installationDate,
|
||||
internetUsername: internetDetails.internetUsername,
|
||||
internetPasswordEncrypted: internetDetails.internetPassword
|
||||
? (0, encryption_js_1.encrypt)(internetDetails.internetPassword)
|
||||
: undefined,
|
||||
homeId: internetDetails.homeId,
|
||||
activationCode: internetDetails.activationCode,
|
||||
phoneNumbers: internetDetails.phoneNumbers && internetDetails.phoneNumbers.length > 0
|
||||
? {
|
||||
create: internetDetails.phoneNumbers.map((pn) => ({
|
||||
phoneNumber: pn.phoneNumber,
|
||||
isMain: pn.isMain ?? false,
|
||||
sipUsername: pn.sipUsername,
|
||||
sipPasswordEncrypted: pn.sipPassword
|
||||
? (0, encryption_js_1.encrypt)(pn.sipPassword)
|
||||
: undefined,
|
||||
sipServer: pn.sipServer,
|
||||
})),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(mobileDetails && data.type === 'MOBILE'
|
||||
? {
|
||||
mobileDetails: {
|
||||
create: {
|
||||
requiresMultisim: mobileDetails.requiresMultisim,
|
||||
dataVolume: mobileDetails.dataVolume,
|
||||
includedMinutes: mobileDetails.includedMinutes,
|
||||
includedSMS: mobileDetails.includedSMS,
|
||||
deviceModel: mobileDetails.deviceModel,
|
||||
deviceImei: mobileDetails.deviceImei,
|
||||
phoneNumber: mobileDetails.phoneNumber,
|
||||
simCardNumber: mobileDetails.simCardNumber,
|
||||
simCards: mobileDetails.simCards
|
||||
? {
|
||||
create: mobileDetails.simCards.map((sc) => ({
|
||||
phoneNumber: sc.phoneNumber,
|
||||
simCardNumber: sc.simCardNumber,
|
||||
pin: sc.pin ? (0, encryption_js_1.encrypt)(sc.pin) : undefined,
|
||||
puk: sc.puk ? (0, encryption_js_1.encrypt)(sc.puk) : undefined,
|
||||
isMultisim: sc.isMultisim ?? false,
|
||||
isMain: sc.isMain ?? false,
|
||||
})),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(tvDetails && data.type === 'TV'
|
||||
? { tvDetails: { create: tvDetails } }
|
||||
: {}),
|
||||
...(carInsuranceDetails && data.type === 'CAR_INSURANCE'
|
||||
? { carInsuranceDetails: { create: carInsuranceDetails } }
|
||||
: {}),
|
||||
},
|
||||
include: {
|
||||
customer: true,
|
||||
address: true,
|
||||
salesPlatform: true,
|
||||
energyDetails: true,
|
||||
internetDetails: { include: { phoneNumbers: true } },
|
||||
mobileDetails: { include: { simCards: true } },
|
||||
tvDetails: true,
|
||||
carInsuranceDetails: true,
|
||||
},
|
||||
});
|
||||
return contract;
|
||||
}
|
||||
async function updateContract(id, data) {
|
||||
const { energyDetails, internetDetails, mobileDetails, tvDetails, carInsuranceDetails, portalPassword, ...contractData } = data;
|
||||
// Encrypt password if provided
|
||||
const portalPasswordEncrypted = portalPassword
|
||||
? (0, encryption_js_1.encrypt)(portalPassword)
|
||||
: undefined;
|
||||
// Update main contract
|
||||
await prisma.contract.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...contractData,
|
||||
...(portalPasswordEncrypted ? { portalPasswordEncrypted } : {}),
|
||||
},
|
||||
});
|
||||
// Update type-specific details
|
||||
if (energyDetails) {
|
||||
await prisma.energyContractDetails.upsert({
|
||||
where: { contractId: id },
|
||||
update: energyDetails,
|
||||
create: { contractId: id, ...energyDetails },
|
||||
});
|
||||
}
|
||||
if (internetDetails) {
|
||||
const { phoneNumbers, internetPassword, ...internetData } = internetDetails;
|
||||
const existing = await prisma.internetContractDetails.findUnique({
|
||||
where: { contractId: id },
|
||||
include: { phoneNumbers: true },
|
||||
});
|
||||
// Prepare internet data with encryption
|
||||
const preparedInternetData = {
|
||||
downloadSpeed: internetData.downloadSpeed,
|
||||
uploadSpeed: internetData.uploadSpeed,
|
||||
routerModel: internetData.routerModel,
|
||||
routerSerialNumber: internetData.routerSerialNumber,
|
||||
installationDate: internetData.installationDate,
|
||||
internetUsername: internetData.internetUsername,
|
||||
// Only update password if new value provided, otherwise keep existing
|
||||
...(internetPassword
|
||||
? { internetPasswordEncrypted: (0, encryption_js_1.encrypt)(internetPassword) }
|
||||
: {}),
|
||||
homeId: internetData.homeId,
|
||||
activationCode: internetData.activationCode,
|
||||
};
|
||||
if (existing) {
|
||||
await prisma.internetContractDetails.update({
|
||||
where: { contractId: id },
|
||||
data: preparedInternetData,
|
||||
});
|
||||
if (phoneNumbers) {
|
||||
// Get existing phone numbers for preserving encrypted passwords
|
||||
const existingPhoneNumbers = existing.phoneNumbers || [];
|
||||
// Delete all existing phone numbers
|
||||
await prisma.phoneNumber.deleteMany({
|
||||
where: { internetContractDetailsId: existing.id },
|
||||
});
|
||||
// Create new phone numbers with encryption
|
||||
await prisma.phoneNumber.createMany({
|
||||
data: phoneNumbers.map((pn) => {
|
||||
// Find existing entry to preserve sipPassword if not changed
|
||||
const existingPn = pn.id
|
||||
? existingPhoneNumbers.find((e) => e.id === pn.id)
|
||||
: undefined;
|
||||
return {
|
||||
internetContractDetailsId: existing.id,
|
||||
phoneNumber: pn.phoneNumber,
|
||||
isMain: pn.isMain ?? false,
|
||||
sipUsername: pn.sipUsername,
|
||||
// Preserve existing sipPassword if no new value provided
|
||||
sipPasswordEncrypted: pn.sipPassword
|
||||
? (0, encryption_js_1.encrypt)(pn.sipPassword)
|
||||
: existingPn?.sipPasswordEncrypted ?? undefined,
|
||||
sipServer: pn.sipServer,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
await prisma.internetContractDetails.create({
|
||||
data: {
|
||||
contractId: id,
|
||||
...preparedInternetData,
|
||||
...(internetPassword
|
||||
? { internetPasswordEncrypted: (0, encryption_js_1.encrypt)(internetPassword) }
|
||||
: {}),
|
||||
phoneNumbers: phoneNumbers
|
||||
? {
|
||||
create: phoneNumbers.map((pn) => ({
|
||||
phoneNumber: pn.phoneNumber,
|
||||
isMain: pn.isMain ?? false,
|
||||
sipUsername: pn.sipUsername,
|
||||
sipPasswordEncrypted: pn.sipPassword
|
||||
? (0, encryption_js_1.encrypt)(pn.sipPassword)
|
||||
: undefined,
|
||||
sipServer: pn.sipServer,
|
||||
})),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
if (mobileDetails) {
|
||||
const { simCards, ...mobileData } = mobileDetails;
|
||||
const existing = await prisma.mobileContractDetails.findUnique({
|
||||
where: { contractId: id },
|
||||
});
|
||||
if (existing) {
|
||||
await prisma.mobileContractDetails.update({
|
||||
where: { contractId: id },
|
||||
data: mobileData,
|
||||
});
|
||||
if (simCards) {
|
||||
// Get existing sim cards to preserve PIN/PUK if not provided
|
||||
const existingSimCards = await prisma.simCard.findMany({
|
||||
where: { mobileDetailsId: existing.id },
|
||||
});
|
||||
const existingSimCardMap = new Map(existingSimCards.map(sc => [sc.id, sc]));
|
||||
// Delete existing sim cards
|
||||
await prisma.simCard.deleteMany({
|
||||
where: { mobileDetailsId: existing.id },
|
||||
});
|
||||
// Create new sim cards, preserving PIN/PUK if not provided
|
||||
await prisma.simCard.createMany({
|
||||
data: simCards.map((sc) => {
|
||||
const existingSc = sc.id ? existingSimCardMap.get(sc.id) : undefined;
|
||||
return {
|
||||
mobileDetailsId: existing.id,
|
||||
phoneNumber: sc.phoneNumber,
|
||||
simCardNumber: sc.simCardNumber,
|
||||
// Preserve existing PIN/PUK if no new value provided
|
||||
pin: sc.pin ? (0, encryption_js_1.encrypt)(sc.pin) : (existingSc?.pin ?? undefined),
|
||||
puk: sc.puk ? (0, encryption_js_1.encrypt)(sc.puk) : (existingSc?.puk ?? undefined),
|
||||
isMultisim: sc.isMultisim ?? false,
|
||||
isMain: sc.isMain ?? false,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
await prisma.mobileContractDetails.create({
|
||||
data: {
|
||||
contractId: id,
|
||||
...mobileData,
|
||||
simCards: simCards
|
||||
? {
|
||||
create: simCards.map((sc) => ({
|
||||
phoneNumber: sc.phoneNumber,
|
||||
simCardNumber: sc.simCardNumber,
|
||||
pin: sc.pin ? (0, encryption_js_1.encrypt)(sc.pin) : undefined,
|
||||
puk: sc.puk ? (0, encryption_js_1.encrypt)(sc.puk) : undefined,
|
||||
isMultisim: sc.isMultisim ?? false,
|
||||
isMain: sc.isMain ?? false,
|
||||
})),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
if (tvDetails) {
|
||||
await prisma.tvContractDetails.upsert({
|
||||
where: { contractId: id },
|
||||
update: tvDetails,
|
||||
create: { contractId: id, ...tvDetails },
|
||||
});
|
||||
}
|
||||
if (carInsuranceDetails) {
|
||||
await prisma.carInsuranceDetails.upsert({
|
||||
where: { contractId: id },
|
||||
update: carInsuranceDetails,
|
||||
create: { contractId: id, ...carInsuranceDetails },
|
||||
});
|
||||
}
|
||||
return getContractById(id);
|
||||
}
|
||||
async function deleteContract(id) {
|
||||
return prisma.contract.delete({ where: { id } });
|
||||
}
|
||||
async function createFollowUpContract(previousContractId) {
|
||||
const previousContract = await getContractById(previousContractId);
|
||||
if (!previousContract) {
|
||||
throw new Error('Vorgängervertrag nicht gefunden');
|
||||
}
|
||||
// Copy data but exclude provider credentials and some fields
|
||||
const newContractData = {
|
||||
customerId: previousContract.customerId,
|
||||
type: previousContract.type,
|
||||
status: 'DRAFT',
|
||||
addressId: previousContract.addressId ?? undefined,
|
||||
bankCardId: previousContract.bankCardId ?? undefined,
|
||||
identityDocumentId: previousContract.identityDocumentId ?? undefined,
|
||||
salesPlatformId: previousContract.salesPlatformId ?? undefined,
|
||||
previousContractId: previousContract.id,
|
||||
// Explicitly NOT copying: providerName, tariffName, portalUsername, portalPassword, price fields
|
||||
cancellationPeriodId: previousContract.cancellationPeriodId ?? undefined,
|
||||
contractDurationId: previousContract.contractDurationId ?? undefined,
|
||||
notes: `Folgevertrag zu ${previousContract.contractNumber}`,
|
||||
};
|
||||
// Copy type-specific details (without credentials)
|
||||
if (previousContract.energyDetails) {
|
||||
newContractData.energyDetails = {
|
||||
meterId: previousContract.energyDetails.meterId ?? undefined,
|
||||
annualConsumption: previousContract.energyDetails.annualConsumption ?? undefined,
|
||||
basePrice: previousContract.energyDetails.basePrice ?? undefined,
|
||||
unitPrice: previousContract.energyDetails.unitPrice ?? undefined,
|
||||
previousProviderName: previousContract.providerName ?? undefined,
|
||||
previousCustomerNumber: previousContract.customerNumberAtProvider ?? undefined,
|
||||
};
|
||||
}
|
||||
if (previousContract.internetDetails) {
|
||||
newContractData.internetDetails = {
|
||||
downloadSpeed: previousContract.internetDetails.downloadSpeed ?? undefined,
|
||||
uploadSpeed: previousContract.internetDetails.uploadSpeed ?? undefined,
|
||||
routerModel: previousContract.internetDetails.routerModel ?? undefined,
|
||||
routerSerialNumber: previousContract.internetDetails.routerSerialNumber ?? undefined,
|
||||
phoneNumbers: previousContract.internetDetails.phoneNumbers.map((pn) => ({
|
||||
phoneNumber: pn.phoneNumber,
|
||||
isMain: pn.isMain,
|
||||
})),
|
||||
};
|
||||
}
|
||||
if (previousContract.mobileDetails) {
|
||||
newContractData.mobileDetails = {
|
||||
requiresMultisim: previousContract.mobileDetails.requiresMultisim ?? undefined,
|
||||
dataVolume: previousContract.mobileDetails.dataVolume ?? undefined,
|
||||
includedMinutes: previousContract.mobileDetails.includedMinutes ?? undefined,
|
||||
includedSMS: previousContract.mobileDetails.includedSMS ?? undefined,
|
||||
deviceModel: previousContract.mobileDetails.deviceModel ?? undefined,
|
||||
deviceImei: previousContract.mobileDetails.deviceImei ?? undefined,
|
||||
phoneNumber: previousContract.mobileDetails.phoneNumber ?? undefined,
|
||||
simCardNumber: previousContract.mobileDetails.simCardNumber ?? undefined,
|
||||
// Copy simCards without PIN/PUK (security)
|
||||
simCards: previousContract.mobileDetails.simCards?.map((sc) => ({
|
||||
phoneNumber: sc.phoneNumber ?? undefined,
|
||||
simCardNumber: sc.simCardNumber ?? undefined,
|
||||
isMultisim: sc.isMultisim,
|
||||
isMain: sc.isMain,
|
||||
})),
|
||||
};
|
||||
}
|
||||
if (previousContract.tvDetails) {
|
||||
newContractData.tvDetails = {
|
||||
receiverModel: previousContract.tvDetails.receiverModel ?? undefined,
|
||||
smartcardNumber: previousContract.tvDetails.smartcardNumber ?? undefined,
|
||||
package: previousContract.tvDetails.package ?? undefined,
|
||||
};
|
||||
}
|
||||
if (previousContract.carInsuranceDetails) {
|
||||
newContractData.carInsuranceDetails = {
|
||||
licensePlate: previousContract.carInsuranceDetails.licensePlate ?? undefined,
|
||||
hsn: previousContract.carInsuranceDetails.hsn ?? undefined,
|
||||
tsn: previousContract.carInsuranceDetails.tsn ?? undefined,
|
||||
vin: previousContract.carInsuranceDetails.vin ?? undefined,
|
||||
vehicleType: previousContract.carInsuranceDetails.vehicleType ?? undefined,
|
||||
firstRegistration: previousContract.carInsuranceDetails.firstRegistration ?? undefined,
|
||||
noClaimsClass: previousContract.carInsuranceDetails.noClaimsClass ?? undefined,
|
||||
insuranceType: previousContract.carInsuranceDetails.insuranceType,
|
||||
deductiblePartial: previousContract.carInsuranceDetails.deductiblePartial ?? undefined,
|
||||
deductibleFull: previousContract.carInsuranceDetails.deductibleFull ?? undefined,
|
||||
previousInsurer: previousContract.providerName ?? undefined,
|
||||
};
|
||||
}
|
||||
return createContract(newContractData);
|
||||
}
|
||||
// Decrypt password for viewing
|
||||
async function getContractPassword(id) {
|
||||
const contract = await prisma.contract.findUnique({
|
||||
where: { id },
|
||||
select: { portalPasswordEncrypted: true },
|
||||
});
|
||||
if (!contract?.portalPasswordEncrypted)
|
||||
return null;
|
||||
try {
|
||||
return (0, encryption_js_1.decrypt)(contract.portalPasswordEncrypted);
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Decrypt SimCard PIN/PUK
|
||||
async function getSimCardCredentials(simCardId) {
|
||||
const simCard = await prisma.simCard.findUnique({
|
||||
where: { id: simCardId },
|
||||
select: { pin: true, puk: true },
|
||||
});
|
||||
if (!simCard)
|
||||
return { pin: null, puk: null };
|
||||
try {
|
||||
return {
|
||||
pin: simCard.pin ? (0, encryption_js_1.decrypt)(simCard.pin) : null,
|
||||
puk: simCard.puk ? (0, encryption_js_1.decrypt)(simCard.puk) : null,
|
||||
};
|
||||
}
|
||||
catch {
|
||||
return { pin: null, puk: null };
|
||||
}
|
||||
}
|
||||
// Decrypt Internet password
|
||||
async function getInternetCredentials(contractId) {
|
||||
const internetDetails = await prisma.internetContractDetails.findUnique({
|
||||
where: { contractId },
|
||||
select: { internetPasswordEncrypted: true },
|
||||
});
|
||||
if (!internetDetails?.internetPasswordEncrypted)
|
||||
return { password: null };
|
||||
try {
|
||||
return {
|
||||
password: (0, encryption_js_1.decrypt)(internetDetails.internetPasswordEncrypted),
|
||||
};
|
||||
}
|
||||
catch {
|
||||
return { password: null };
|
||||
}
|
||||
}
|
||||
// Decrypt SIP password for a phone number
|
||||
async function getSipCredentials(phoneNumberId) {
|
||||
const phoneNumber = await prisma.phoneNumber.findUnique({
|
||||
where: { id: phoneNumberId },
|
||||
select: { sipPasswordEncrypted: true },
|
||||
});
|
||||
if (!phoneNumber?.sipPasswordEncrypted)
|
||||
return { password: null };
|
||||
try {
|
||||
return {
|
||||
password: (0, encryption_js_1.decrypt)(phoneNumber.sipPasswordEncrypted),
|
||||
};
|
||||
}
|
||||
catch {
|
||||
return { password: null };
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=contract.service.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,92 @@
|
||||
export declare function getAllContractCategories(includeInactive?: boolean): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
code: string;
|
||||
icon: string | null;
|
||||
color: string | null;
|
||||
sortOrder: number;
|
||||
})[]>;
|
||||
export declare function getContractCategoryById(id: number): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
code: string;
|
||||
icon: string | null;
|
||||
color: string | null;
|
||||
sortOrder: number;
|
||||
}) | null>;
|
||||
export declare function getContractCategoryByCode(code: string): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
code: string;
|
||||
icon: string | null;
|
||||
color: string | null;
|
||||
sortOrder: number;
|
||||
} | null>;
|
||||
interface ContractCategoryCreateData {
|
||||
code: string;
|
||||
name: string;
|
||||
icon?: string;
|
||||
color?: string;
|
||||
sortOrder?: number;
|
||||
isActive?: boolean;
|
||||
}
|
||||
export declare function createContractCategory(data: ContractCategoryCreateData): Promise<{
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
code: string;
|
||||
icon: string | null;
|
||||
color: string | null;
|
||||
sortOrder: number;
|
||||
}>;
|
||||
export declare function updateContractCategory(id: number, data: Partial<ContractCategoryCreateData>): Promise<{
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
code: string;
|
||||
icon: string | null;
|
||||
color: string | null;
|
||||
sortOrder: number;
|
||||
}>;
|
||||
export declare function deleteContractCategory(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
code: string;
|
||||
icon: string | null;
|
||||
color: string | null;
|
||||
sortOrder: number;
|
||||
}>;
|
||||
export {};
|
||||
//# sourceMappingURL=contractCategory.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"contractCategory.service.d.ts","sourceRoot":"","sources":["../../src/services/contractCategory.service.ts"],"names":[],"mappings":"AAIA,wBAAsB,wBAAwB,CAAC,eAAe,UAAQ;;;;;;;;;;;;;;MAUrE;AAED,wBAAsB,uBAAuB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;WASvD;AAED,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM;;;;;;;;;;UAI3D;AAED,UAAU,0BAA0B;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,0BAA0B;;;;;;;;;;;;;;GAS5E;AAED,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,0BAA0B,CAAC;;;;;;;;;;;;;;GAUjG;AAED,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;GAYtD"}
|
||||
@@ -0,0 +1,69 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllContractCategories = getAllContractCategories;
|
||||
exports.getContractCategoryById = getContractCategoryById;
|
||||
exports.getContractCategoryByCode = getContractCategoryByCode;
|
||||
exports.createContractCategory = createContractCategory;
|
||||
exports.updateContractCategory = updateContractCategory;
|
||||
exports.deleteContractCategory = deleteContractCategory;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getAllContractCategories(includeInactive = false) {
|
||||
return prisma.contractCategory.findMany({
|
||||
where: includeInactive ? {} : { isActive: true },
|
||||
orderBy: [{ sortOrder: 'asc' }, { name: 'asc' }],
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function getContractCategoryById(id) {
|
||||
return prisma.contractCategory.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function getContractCategoryByCode(code) {
|
||||
return prisma.contractCategory.findUnique({
|
||||
where: { code },
|
||||
});
|
||||
}
|
||||
async function createContractCategory(data) {
|
||||
return prisma.contractCategory.create({
|
||||
data,
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateContractCategory(id, data) {
|
||||
return prisma.contractCategory.update({
|
||||
where: { id },
|
||||
data,
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function deleteContractCategory(id) {
|
||||
// Check if category has contracts
|
||||
const category = await prisma.contractCategory.findUnique({
|
||||
where: { id },
|
||||
include: { _count: { select: { contracts: true } } },
|
||||
});
|
||||
if (category && category._count.contracts > 0) {
|
||||
throw new Error(`Kategorie kann nicht gelöscht werden, da ${category._count.contracts} Verträge zugeordnet sind.`);
|
||||
}
|
||||
return prisma.contractCategory.delete({ where: { id } });
|
||||
}
|
||||
//# sourceMappingURL=contractCategory.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"contractCategory.service.js","sourceRoot":"","sources":["../../src/services/contractCategory.service.ts"],"names":[],"mappings":";;AAIA,4DAUC;AAED,0DASC;AAED,8DAIC;AAWD,wDASC;AAED,wDAUC;AAED,wDAYC;AA7ED,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAE3B,KAAK,UAAU,wBAAwB,CAAC,eAAe,GAAG,KAAK;IACpE,OAAO,MAAM,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QACtC,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;QAChD,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAChD,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,uBAAuB,CAAC,EAAU;IACtD,OAAO,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC;QACxC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,yBAAyB,CAAC,IAAY;IAC1D,OAAO,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC;QACxC,KAAK,EAAE,EAAE,IAAI,EAAE;KAChB,CAAC,CAAC;AACL,CAAC;AAWM,KAAK,UAAU,sBAAsB,CAAC,IAAgC;IAC3E,OAAO,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACpC,IAAI;QACJ,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAAC,EAAU,EAAE,IAAyC;IAChG,OAAO,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACpC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;QACJ,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,sBAAsB,CAAC,EAAU;IACrD,kCAAkC;IAClC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC;QACxD,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE;KACrD,CAAC,CAAC;IAEH,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,CAAC,MAAM,CAAC,SAAS,4BAA4B,CAAC,CAAC;IACrH,CAAC;IAED,OAAO,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC3D,CAAC"}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { ContractStatus } from '@prisma/client';
|
||||
export type UrgencyLevel = 'critical' | 'warning' | 'ok' | 'none';
|
||||
export interface CockpitIssue {
|
||||
type: string;
|
||||
label: string;
|
||||
urgency: UrgencyLevel;
|
||||
daysRemaining?: number;
|
||||
details?: string;
|
||||
}
|
||||
export interface CockpitContract {
|
||||
id: number;
|
||||
contractNumber: string;
|
||||
type: string;
|
||||
status: ContractStatus;
|
||||
customer: {
|
||||
id: number;
|
||||
customerNumber: string;
|
||||
name: string;
|
||||
};
|
||||
provider?: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
tariff?: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
providerName?: string;
|
||||
tariffName?: string;
|
||||
issues: CockpitIssue[];
|
||||
highestUrgency: UrgencyLevel;
|
||||
}
|
||||
export interface CockpitSummary {
|
||||
totalContracts: number;
|
||||
criticalCount: number;
|
||||
warningCount: number;
|
||||
okCount: number;
|
||||
byCategory: {
|
||||
cancellationDeadlines: number;
|
||||
contractEnding: number;
|
||||
missingCredentials: number;
|
||||
missingData: number;
|
||||
openTasks: number;
|
||||
pendingContracts: number;
|
||||
};
|
||||
}
|
||||
export interface CockpitResult {
|
||||
contracts: CockpitContract[];
|
||||
summary: CockpitSummary;
|
||||
thresholds: {
|
||||
criticalDays: number;
|
||||
warningDays: number;
|
||||
okDays: number;
|
||||
};
|
||||
}
|
||||
export declare function getCockpitData(): Promise<CockpitResult>;
|
||||
//# sourceMappingURL=contractCockpit.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"contractCockpit.service.d.ts","sourceRoot":"","sources":["../../src/services/contractCockpit.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,cAAc,EACpC,MAAM,gBAAgB,CAAC;AAMxB,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC;AAElE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE;QACR,EAAE,EAAE,MAAM,CAAC;QACX,cAAc,EAAE,MAAM,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,MAAM,CAAC,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,cAAc,EAAE,YAAY,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE;QACV,qBAAqB,EAAE,MAAM,CAAC;QAC9B,cAAc,EAAE,MAAM,CAAC;QACvB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAyED,wBAAsB,cAAc,IAAI,OAAO,CAAC,aAAa,CAAC,CAiV7D"}
|
||||
+416
@@ -0,0 +1,416 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getCockpitData = getCockpitData;
|
||||
const client_1 = require("@prisma/client");
|
||||
const appSettingService = __importStar(require("./appSetting.service.js"));
|
||||
const prisma = new client_1.PrismaClient();
|
||||
// Hilfsfunktion: Tage bis zu einem Datum berechnen
|
||||
function daysUntil(date) {
|
||||
if (!date)
|
||||
return null;
|
||||
const now = new Date();
|
||||
now.setHours(0, 0, 0, 0);
|
||||
const target = new Date(date);
|
||||
target.setHours(0, 0, 0, 0);
|
||||
const diff = target.getTime() - now.getTime();
|
||||
return Math.ceil(diff / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
// Hilfsfunktion: Urgency basierend auf Tagen bestimmen
|
||||
function getUrgencyByDays(daysRemaining, criticalDays, warningDays, okDays) {
|
||||
if (daysRemaining === null)
|
||||
return 'none';
|
||||
if (daysRemaining < 0)
|
||||
return 'critical'; // Bereits überfällig
|
||||
if (daysRemaining <= criticalDays)
|
||||
return 'critical';
|
||||
if (daysRemaining <= warningDays)
|
||||
return 'warning';
|
||||
if (daysRemaining <= okDays)
|
||||
return 'ok';
|
||||
return 'none';
|
||||
}
|
||||
// Hilfsfunktion: Höchste Dringlichkeit ermitteln
|
||||
function getHighestUrgency(issues) {
|
||||
const levels = ['critical', 'warning', 'ok', 'none'];
|
||||
for (const level of levels) {
|
||||
if (issues.some(i => i.urgency === level)) {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
return 'none';
|
||||
}
|
||||
// Kündigungsfrist berechnen
|
||||
function calculateCancellationDeadline(endDate, cancellationPeriodCode) {
|
||||
if (!endDate || !cancellationPeriodCode)
|
||||
return null;
|
||||
const end = new Date(endDate);
|
||||
// Parse Kündigungsperiode (z.B. "1M" = 1 Monat, "6W" = 6 Wochen, "14D" = 14 Tage)
|
||||
const match = cancellationPeriodCode.match(/^(\d+)([DMWY])$/i);
|
||||
if (!match)
|
||||
return null;
|
||||
const amount = parseInt(match[1]);
|
||||
const unit = match[2].toUpperCase();
|
||||
switch (unit) {
|
||||
case 'D':
|
||||
end.setDate(end.getDate() - amount);
|
||||
break;
|
||||
case 'W':
|
||||
end.setDate(end.getDate() - (amount * 7));
|
||||
break;
|
||||
case 'M':
|
||||
end.setMonth(end.getMonth() - amount);
|
||||
break;
|
||||
case 'Y':
|
||||
end.setFullYear(end.getFullYear() - amount);
|
||||
break;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
async function getCockpitData() {
|
||||
// Lade Einstellungen
|
||||
const settings = await appSettingService.getAllSettings();
|
||||
const criticalDays = parseInt(settings.deadlineCriticalDays) || 14;
|
||||
const warningDays = parseInt(settings.deadlineWarningDays) || 42;
|
||||
const okDays = parseInt(settings.deadlineOkDays) || 90;
|
||||
// Lade alle aktiven/pending Verträge mit allen relevanten Daten
|
||||
const contracts = await prisma.contract.findMany({
|
||||
where: {
|
||||
status: {
|
||||
in: ['ACTIVE', 'PENDING', 'DRAFT'],
|
||||
},
|
||||
},
|
||||
include: {
|
||||
customer: {
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
},
|
||||
},
|
||||
provider: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
tariff: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
cancellationPeriod: {
|
||||
select: {
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
address: true,
|
||||
bankCard: true,
|
||||
identityDocument: true,
|
||||
energyDetails: {
|
||||
include: {
|
||||
meter: true,
|
||||
},
|
||||
},
|
||||
internetDetails: {
|
||||
include: {
|
||||
phoneNumbers: true,
|
||||
},
|
||||
},
|
||||
mobileDetails: {
|
||||
include: {
|
||||
simCards: true,
|
||||
},
|
||||
},
|
||||
tasks: {
|
||||
where: {
|
||||
status: 'OPEN',
|
||||
},
|
||||
},
|
||||
// Folgevertrag laden um zu prüfen ob dieser aktiv ist
|
||||
followUpContract: {
|
||||
select: {
|
||||
id: true,
|
||||
status: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: [
|
||||
{ endDate: 'asc' },
|
||||
{ createdAt: 'desc' },
|
||||
],
|
||||
});
|
||||
const cockpitContracts = [];
|
||||
const summary = {
|
||||
totalContracts: 0,
|
||||
criticalCount: 0,
|
||||
warningCount: 0,
|
||||
okCount: 0,
|
||||
byCategory: {
|
||||
cancellationDeadlines: 0,
|
||||
contractEnding: 0,
|
||||
missingCredentials: 0,
|
||||
missingData: 0,
|
||||
openTasks: 0,
|
||||
pendingContracts: 0,
|
||||
},
|
||||
};
|
||||
for (const contract of contracts) {
|
||||
const issues = [];
|
||||
// Prüfen ob aktiver Folgevertrag existiert - dann keine Kündigungswarnungen nötig
|
||||
const hasActiveFollowUp = contract.followUpContract?.status === 'ACTIVE';
|
||||
// 1. KÜNDIGUNGSFRIST (nur wenn kein aktiver Folgevertrag)
|
||||
if (!hasActiveFollowUp) {
|
||||
const cancellationDeadline = calculateCancellationDeadline(contract.endDate, contract.cancellationPeriod?.code);
|
||||
const daysToCancellation = daysUntil(cancellationDeadline);
|
||||
if (daysToCancellation !== null && daysToCancellation <= okDays) {
|
||||
const urgency = getUrgencyByDays(daysToCancellation, criticalDays, warningDays, okDays);
|
||||
if (urgency !== 'none') {
|
||||
issues.push({
|
||||
type: 'cancellation_deadline',
|
||||
label: 'Kündigungsfrist',
|
||||
urgency,
|
||||
daysRemaining: daysToCancellation,
|
||||
details: daysToCancellation < 0
|
||||
? `Frist seit ${Math.abs(daysToCancellation)} Tagen überschritten!`
|
||||
: `Noch ${daysToCancellation} Tage bis zur Kündigungsfrist`,
|
||||
});
|
||||
summary.byCategory.cancellationDeadlines++;
|
||||
}
|
||||
// 1a. KÜNDIGUNG NICHT GESENDET (wenn Frist naht)
|
||||
if (!contract.cancellationLetterPath) {
|
||||
issues.push({
|
||||
type: 'missing_cancellation_letter',
|
||||
label: 'Kündigung nicht gesendet',
|
||||
urgency,
|
||||
details: 'Kündigungsschreiben wurde noch nicht hochgeladen',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
// 1b. KÜNDIGUNGSBESTÄTIGUNG FEHLT (wenn Kündigung gesendet aber keine Bestätigung)
|
||||
if (contract.cancellationLetterPath && !contract.cancellationConfirmationPath && !contract.cancellationConfirmationDate) {
|
||||
issues.push({
|
||||
type: 'missing_cancellation_confirmation',
|
||||
label: 'Kündigungsbestätigung fehlt',
|
||||
urgency: urgency === 'critical' ? 'critical' : 'warning',
|
||||
details: 'Kündigungsbestätigung vom Anbieter wurde noch nicht erhalten',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. VERTRAGSENDE
|
||||
const daysToEnd = daysUntil(contract.endDate);
|
||||
if (daysToEnd !== null && daysToEnd <= okDays) {
|
||||
const urgency = getUrgencyByDays(daysToEnd, criticalDays, warningDays, okDays);
|
||||
if (urgency !== 'none') {
|
||||
issues.push({
|
||||
type: 'contract_ending',
|
||||
label: 'Vertragsende',
|
||||
urgency,
|
||||
daysRemaining: daysToEnd,
|
||||
details: daysToEnd < 0
|
||||
? `Vertrag seit ${Math.abs(daysToEnd)} Tagen abgelaufen!`
|
||||
: `Noch ${daysToEnd} Tage bis Vertragsende`,
|
||||
});
|
||||
summary.byCategory.contractEnding++;
|
||||
}
|
||||
}
|
||||
// 3. FEHLENDE PORTAL-ZUGANGSDATEN
|
||||
if (!contract.portalUsername || !contract.portalPasswordEncrypted) {
|
||||
issues.push({
|
||||
type: 'missing_portal_credentials',
|
||||
label: 'Portal-Zugangsdaten fehlen',
|
||||
urgency: 'warning',
|
||||
details: 'Benutzername oder Passwort für das Anbieter-Portal fehlt',
|
||||
});
|
||||
summary.byCategory.missingCredentials++;
|
||||
}
|
||||
// 4. KEINE KUNDENNUMMER BEIM ANBIETER
|
||||
if (!contract.customerNumberAtProvider) {
|
||||
issues.push({
|
||||
type: 'missing_customer_number',
|
||||
label: 'Kundennummer fehlt',
|
||||
urgency: 'warning',
|
||||
details: 'Kundennummer beim Anbieter fehlt',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
// 5. KEIN ANBIETER/TARIF
|
||||
if (!contract.providerId && !contract.providerName) {
|
||||
issues.push({
|
||||
type: 'missing_provider',
|
||||
label: 'Anbieter fehlt',
|
||||
urgency: 'warning',
|
||||
details: 'Kein Anbieter ausgewählt',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
// 6. KEINE ADRESSE
|
||||
if (!contract.addressId) {
|
||||
issues.push({
|
||||
type: 'missing_address',
|
||||
label: 'Adresse fehlt',
|
||||
urgency: 'warning',
|
||||
details: 'Keine Lieferadresse verknüpft',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
// 7. KEINE BANKVERBINDUNG
|
||||
if (!contract.bankCardId) {
|
||||
issues.push({
|
||||
type: 'missing_bank',
|
||||
label: 'Bankverbindung fehlt',
|
||||
urgency: 'warning',
|
||||
details: 'Keine Bankverbindung verknüpft',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
// 8. ENERGIE-SPEZIFISCH: KEIN ZÄHLER
|
||||
if (['ELECTRICITY', 'GAS'].includes(contract.type) && contract.energyDetails) {
|
||||
if (!contract.energyDetails.meterId) {
|
||||
issues.push({
|
||||
type: 'missing_meter',
|
||||
label: 'Zähler fehlt',
|
||||
urgency: 'warning',
|
||||
details: 'Kein Zähler verknüpft',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
}
|
||||
// 9. MOBIL-SPEZIFISCH: SIM-KARTEN
|
||||
if (contract.type === 'MOBILE' && contract.mobileDetails) {
|
||||
if (!contract.mobileDetails.simCards || contract.mobileDetails.simCards.length === 0) {
|
||||
issues.push({
|
||||
type: 'missing_sim',
|
||||
label: 'SIM-Karte fehlt',
|
||||
urgency: 'warning',
|
||||
details: 'Keine SIM-Karte eingetragen',
|
||||
});
|
||||
summary.byCategory.missingData++;
|
||||
}
|
||||
}
|
||||
// 10. OFFENE AUFGABEN
|
||||
if (contract.tasks && contract.tasks.length > 0) {
|
||||
issues.push({
|
||||
type: 'open_tasks',
|
||||
label: 'Offene Aufgaben',
|
||||
urgency: 'ok',
|
||||
details: `${contract.tasks.length} offene Aufgabe(n)`,
|
||||
});
|
||||
summary.byCategory.openTasks++;
|
||||
}
|
||||
// 11. PENDING STATUS
|
||||
if (contract.status === 'PENDING') {
|
||||
issues.push({
|
||||
type: 'pending_status',
|
||||
label: 'Warte auf Aktivierung',
|
||||
urgency: 'ok',
|
||||
details: 'Vertrag noch nicht aktiv',
|
||||
});
|
||||
summary.byCategory.pendingContracts++;
|
||||
}
|
||||
// 12. DRAFT STATUS
|
||||
if (contract.status === 'DRAFT') {
|
||||
issues.push({
|
||||
type: 'draft_status',
|
||||
label: 'Entwurf',
|
||||
urgency: 'warning',
|
||||
details: 'Vertrag ist noch ein Entwurf',
|
||||
});
|
||||
summary.byCategory.pendingContracts++;
|
||||
}
|
||||
// Nur Verträge mit Issues hinzufügen
|
||||
if (issues.length > 0) {
|
||||
const highestUrgency = getHighestUrgency(issues);
|
||||
const customerName = contract.customer.companyName ||
|
||||
`${contract.customer.firstName} ${contract.customer.lastName}`;
|
||||
cockpitContracts.push({
|
||||
id: contract.id,
|
||||
contractNumber: contract.contractNumber,
|
||||
type: contract.type,
|
||||
status: contract.status,
|
||||
customer: {
|
||||
id: contract.customer.id,
|
||||
customerNumber: contract.customer.customerNumber,
|
||||
name: customerName,
|
||||
},
|
||||
provider: contract.provider ? {
|
||||
id: contract.provider.id,
|
||||
name: contract.provider.name,
|
||||
} : undefined,
|
||||
tariff: contract.tariff ? {
|
||||
id: contract.tariff.id,
|
||||
name: contract.tariff.name,
|
||||
} : undefined,
|
||||
providerName: contract.providerName || undefined,
|
||||
tariffName: contract.tariffName || undefined,
|
||||
issues,
|
||||
highestUrgency,
|
||||
});
|
||||
// Summary zählen
|
||||
summary.totalContracts++;
|
||||
if (highestUrgency === 'critical')
|
||||
summary.criticalCount++;
|
||||
else if (highestUrgency === 'warning')
|
||||
summary.warningCount++;
|
||||
else if (highestUrgency === 'ok')
|
||||
summary.okCount++;
|
||||
}
|
||||
}
|
||||
// Sortiere nach Dringlichkeit
|
||||
cockpitContracts.sort((a, b) => {
|
||||
const urgencyOrder = {
|
||||
critical: 0,
|
||||
warning: 1,
|
||||
ok: 2,
|
||||
none: 3,
|
||||
};
|
||||
return urgencyOrder[a.highestUrgency] - urgencyOrder[b.highestUrgency];
|
||||
});
|
||||
return {
|
||||
contracts: cockpitContracts,
|
||||
summary,
|
||||
thresholds: {
|
||||
criticalDays,
|
||||
warningDays,
|
||||
okDays,
|
||||
},
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=contractCockpit.service.js.map
|
||||
File diff suppressed because one or more lines are too long
+246
@@ -0,0 +1,246 @@
|
||||
import { ContractTaskStatus } from '@prisma/client';
|
||||
export interface ContractTaskFilters {
|
||||
contractId: number;
|
||||
status?: ContractTaskStatus;
|
||||
visibleInPortal?: boolean;
|
||||
customerPortalEmails?: string[];
|
||||
}
|
||||
export declare function getTasksByContract(filters: ContractTaskFilters): Promise<({
|
||||
subtasks: {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
})[]>;
|
||||
export declare function getTaskById(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
} | null>;
|
||||
export declare function createTask(data: {
|
||||
contractId: number;
|
||||
title: string;
|
||||
description?: string;
|
||||
visibleInPortal?: boolean;
|
||||
createdBy?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
}>;
|
||||
export declare function updateTask(id: number, data: {
|
||||
title?: string;
|
||||
description?: string;
|
||||
visibleInPortal?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
}>;
|
||||
export declare function completeTask(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
}>;
|
||||
export declare function reopenTask(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
}>;
|
||||
export declare function deleteTask(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
}>;
|
||||
export declare function createSubtask(data: {
|
||||
taskId: number;
|
||||
title: string;
|
||||
createdBy?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}>;
|
||||
export declare function updateSubtask(id: number, data: {
|
||||
title?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}>;
|
||||
export declare function completeSubtask(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}>;
|
||||
export declare function reopenSubtask(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}>;
|
||||
export declare function deleteSubtask(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}>;
|
||||
export declare function getSubtaskById(id: number): Promise<({
|
||||
task: {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}) | null>;
|
||||
export interface AllTasksFilters {
|
||||
status?: ContractTaskStatus;
|
||||
customerId?: number;
|
||||
customerPortalCustomerIds?: number[];
|
||||
customerPortalEmails?: string[];
|
||||
}
|
||||
export declare function getAllTasks(filters: AllTasksFilters): Promise<({
|
||||
contract: {
|
||||
id: number;
|
||||
customerId: number;
|
||||
customer: {
|
||||
id: number;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
customerNumber: string;
|
||||
companyName: string | null;
|
||||
};
|
||||
tariff: {
|
||||
id: number;
|
||||
name: string;
|
||||
} | null;
|
||||
provider: {
|
||||
id: number;
|
||||
name: string;
|
||||
} | null;
|
||||
tariffName: string | null;
|
||||
providerName: string | null;
|
||||
contractNumber: string;
|
||||
};
|
||||
subtasks: {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
title: string;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
taskId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
description: string | null;
|
||||
status: import(".prisma/client").$Enums.ContractTaskStatus;
|
||||
contractId: number;
|
||||
title: string;
|
||||
visibleInPortal: boolean;
|
||||
createdBy: string | null;
|
||||
completedAt: Date | null;
|
||||
})[]>;
|
||||
export declare function getTaskStats(filters: AllTasksFilters): Promise<{
|
||||
openCount: number;
|
||||
}>;
|
||||
//# sourceMappingURL=contractTask.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"contractTask.service.d.ts","sourceRoot":"","sources":["../../src/services/contractTask.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAIlE,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;;;;;MAsCpE;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;UAI3C;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;;;;;;;;;;;GAUA;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;;;;;;;;;;;GAMF;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;GAQ5C;AAED,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;GAQ1C;AAED,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;GAI1C;AAID,wBAAsB,aAAa,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAQ9F;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE;;;;;;;;;GAKvE;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM;;;;;;;;;GA8B/C;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM;;;;;;;;;GA0B7C;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM;;;;;;;;;GAI7C;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;WAK9C;AAID,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,yBAAyB,CAAC,EAAE,MAAM,EAAE,CAAC;IACrC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA0EzD;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,eAAe;;GA6B1D"}
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getTasksByContract = getTasksByContract;
|
||||
exports.getTaskById = getTaskById;
|
||||
exports.createTask = createTask;
|
||||
exports.updateTask = updateTask;
|
||||
exports.completeTask = completeTask;
|
||||
exports.reopenTask = reopenTask;
|
||||
exports.deleteTask = deleteTask;
|
||||
exports.createSubtask = createSubtask;
|
||||
exports.updateSubtask = updateSubtask;
|
||||
exports.completeSubtask = completeSubtask;
|
||||
exports.reopenSubtask = reopenSubtask;
|
||||
exports.deleteSubtask = deleteSubtask;
|
||||
exports.getSubtaskById = getSubtaskById;
|
||||
exports.getAllTasks = getAllTasks;
|
||||
exports.getTaskStats = getTaskStats;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getTasksByContract(filters) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const where = {
|
||||
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' },
|
||||
],
|
||||
});
|
||||
}
|
||||
async function getTaskById(id) {
|
||||
return prisma.contractTask.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
async function createTask(data) {
|
||||
return prisma.contractTask.create({
|
||||
data: {
|
||||
contractId: data.contractId,
|
||||
title: data.title,
|
||||
description: data.description,
|
||||
visibleInPortal: data.visibleInPortal ?? false,
|
||||
createdBy: data.createdBy,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateTask(id, data) {
|
||||
return prisma.contractTask.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function completeTask(id) {
|
||||
return prisma.contractTask.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: 'COMPLETED',
|
||||
completedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
async function reopenTask(id) {
|
||||
return prisma.contractTask.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: 'OPEN',
|
||||
completedAt: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function deleteTask(id) {
|
||||
return prisma.contractTask.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
// ==================== SUBTASKS ====================
|
||||
async function createSubtask(data) {
|
||||
return prisma.contractTaskSubtask.create({
|
||||
data: {
|
||||
taskId: data.taskId,
|
||||
title: data.title,
|
||||
createdBy: data.createdBy,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateSubtask(id, data) {
|
||||
return prisma.contractTaskSubtask.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function completeSubtask(id) {
|
||||
// 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;
|
||||
}
|
||||
async function reopenSubtask(id) {
|
||||
// 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;
|
||||
}
|
||||
async function deleteSubtask(id) {
|
||||
return prisma.contractTaskSubtask.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
async function getSubtaskById(id) {
|
||||
return prisma.contractTaskSubtask.findUnique({
|
||||
where: { id },
|
||||
include: { task: true },
|
||||
});
|
||||
}
|
||||
async function getAllTasks(filters) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const where = {};
|
||||
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' },
|
||||
],
|
||||
});
|
||||
}
|
||||
async function getTaskStats(filters) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const where = {
|
||||
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 };
|
||||
}
|
||||
//# sourceMappingURL=contractTask.service.js.map
|
||||
File diff suppressed because one or more lines are too long
+747
@@ -0,0 +1,747 @@
|
||||
import { CustomerType } from '@prisma/client';
|
||||
export interface CustomerFilters {
|
||||
search?: string;
|
||||
type?: CustomerType;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}
|
||||
export declare function getAllCustomers(filters: CustomerFilters): Promise<{
|
||||
customers: ({
|
||||
addresses: {
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.AddressType;
|
||||
isDefault: boolean;
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country: string;
|
||||
}[];
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
email: string | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
customerNumber: string;
|
||||
portalEmail: string | null;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
salutation: string | null;
|
||||
companyName: string | null;
|
||||
foundingDate: Date | null;
|
||||
birthDate: Date | null;
|
||||
birthPlace: string | null;
|
||||
phone: string | null;
|
||||
mobile: string | null;
|
||||
taxNumber: string | null;
|
||||
businessRegistrationPath: string | null;
|
||||
commercialRegisterPath: string | null;
|
||||
commercialRegisterNumber: string | null;
|
||||
privacyPolicyPath: string | null;
|
||||
notes: string | null;
|
||||
portalEnabled: boolean;
|
||||
portalPasswordHash: string | null;
|
||||
portalPasswordEncrypted: string | null;
|
||||
portalLastLogin: Date | null;
|
||||
})[];
|
||||
pagination: {
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
totalPages: number;
|
||||
};
|
||||
}>;
|
||||
export declare function getCustomerById(id: number): Promise<({
|
||||
addresses: {
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.AddressType;
|
||||
isDefault: boolean;
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country: string;
|
||||
}[];
|
||||
bankCards: {
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
accountHolder: string;
|
||||
iban: string;
|
||||
bic: string | null;
|
||||
bankName: string | null;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
}[];
|
||||
identityDocuments: {
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.DocumentType;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
documentNumber: string;
|
||||
issuingAuthority: string | null;
|
||||
issueDate: Date | null;
|
||||
licenseClasses: string | null;
|
||||
licenseIssueDate: Date | null;
|
||||
}[];
|
||||
meters: ({
|
||||
readings: {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
notes: string | null;
|
||||
readingDate: Date;
|
||||
value: number;
|
||||
unit: string;
|
||||
meterId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.MeterType;
|
||||
meterNumber: string;
|
||||
location: string | null;
|
||||
})[];
|
||||
stressfreiEmails: {
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
platform: string | null;
|
||||
isProvisioned: boolean;
|
||||
provisionedAt: Date | null;
|
||||
provisionError: string | null;
|
||||
}[];
|
||||
contracts: ({
|
||||
address: {
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.AddressType;
|
||||
isDefault: boolean;
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country: string;
|
||||
} | null;
|
||||
salesPlatform: {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
contactInfo: string | null;
|
||||
} | null;
|
||||
} & {
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.ContractType;
|
||||
notes: string | null;
|
||||
portalPasswordEncrypted: string | null;
|
||||
startDate: Date | null;
|
||||
status: import(".prisma/client").$Enums.ContractStatus;
|
||||
customerNumberAtProvider: string | null;
|
||||
tariffName: string | null;
|
||||
providerName: string | null;
|
||||
contractNumber: string;
|
||||
contractCategoryId: number | null;
|
||||
addressId: number | null;
|
||||
bankCardId: number | null;
|
||||
identityDocumentId: number | null;
|
||||
salesPlatformId: number | null;
|
||||
cancellationPeriodId: number | null;
|
||||
contractDurationId: number | null;
|
||||
previousContractId: number | null;
|
||||
providerId: number | null;
|
||||
tariffId: number | null;
|
||||
priceFirst12Months: string | null;
|
||||
priceFrom13Months: string | null;
|
||||
priceAfter24Months: string | null;
|
||||
endDate: Date | null;
|
||||
commission: number | null;
|
||||
cancellationLetterPath: string | null;
|
||||
cancellationConfirmationPath: string | null;
|
||||
cancellationLetterOptionsPath: string | null;
|
||||
cancellationConfirmationOptionsPath: string | null;
|
||||
cancellationConfirmationDate: Date | null;
|
||||
cancellationConfirmationOptionsDate: Date | null;
|
||||
wasSpecialCancellation: boolean;
|
||||
portalUsername: string | null;
|
||||
stressfreiEmailId: number | null;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
email: string | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
customerNumber: string;
|
||||
portalEmail: string | null;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
salutation: string | null;
|
||||
companyName: string | null;
|
||||
foundingDate: Date | null;
|
||||
birthDate: Date | null;
|
||||
birthPlace: string | null;
|
||||
phone: string | null;
|
||||
mobile: string | null;
|
||||
taxNumber: string | null;
|
||||
businessRegistrationPath: string | null;
|
||||
commercialRegisterPath: string | null;
|
||||
commercialRegisterNumber: string | null;
|
||||
privacyPolicyPath: string | null;
|
||||
notes: string | null;
|
||||
portalEnabled: boolean;
|
||||
portalPasswordHash: string | null;
|
||||
portalPasswordEncrypted: string | null;
|
||||
portalLastLogin: Date | null;
|
||||
}) | null>;
|
||||
export declare function getCustomersByIds(ids: number[]): Promise<{
|
||||
id: number;
|
||||
portalEmail: string | null;
|
||||
}[]>;
|
||||
export declare function createCustomer(data: {
|
||||
type?: CustomerType;
|
||||
salutation?: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
companyName?: string;
|
||||
birthDate?: Date;
|
||||
birthPlace?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
mobile?: string;
|
||||
taxNumber?: string;
|
||||
businessRegistration?: string;
|
||||
commercialRegister?: string;
|
||||
notes?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
email: string | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
customerNumber: string;
|
||||
portalEmail: string | null;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
salutation: string | null;
|
||||
companyName: string | null;
|
||||
foundingDate: Date | null;
|
||||
birthDate: Date | null;
|
||||
birthPlace: string | null;
|
||||
phone: string | null;
|
||||
mobile: string | null;
|
||||
taxNumber: string | null;
|
||||
businessRegistrationPath: string | null;
|
||||
commercialRegisterPath: string | null;
|
||||
commercialRegisterNumber: string | null;
|
||||
privacyPolicyPath: string | null;
|
||||
notes: string | null;
|
||||
portalEnabled: boolean;
|
||||
portalPasswordHash: string | null;
|
||||
portalPasswordEncrypted: string | null;
|
||||
portalLastLogin: Date | null;
|
||||
}>;
|
||||
export declare function updateCustomer(id: number, data: {
|
||||
type?: CustomerType;
|
||||
salutation?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
companyName?: string;
|
||||
birthDate?: Date;
|
||||
birthPlace?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
mobile?: string;
|
||||
taxNumber?: string;
|
||||
businessRegistration?: string;
|
||||
commercialRegister?: string;
|
||||
notes?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
email: string | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
customerNumber: string;
|
||||
portalEmail: string | null;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
salutation: string | null;
|
||||
companyName: string | null;
|
||||
foundingDate: Date | null;
|
||||
birthDate: Date | null;
|
||||
birthPlace: string | null;
|
||||
phone: string | null;
|
||||
mobile: string | null;
|
||||
taxNumber: string | null;
|
||||
businessRegistrationPath: string | null;
|
||||
commercialRegisterPath: string | null;
|
||||
commercialRegisterNumber: string | null;
|
||||
privacyPolicyPath: string | null;
|
||||
notes: string | null;
|
||||
portalEnabled: boolean;
|
||||
portalPasswordHash: string | null;
|
||||
portalPasswordEncrypted: string | null;
|
||||
portalLastLogin: Date | null;
|
||||
}>;
|
||||
export declare function deleteCustomer(id: number): Promise<{
|
||||
id: number;
|
||||
email: string | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
customerNumber: string;
|
||||
portalEmail: string | null;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
salutation: string | null;
|
||||
companyName: string | null;
|
||||
foundingDate: Date | null;
|
||||
birthDate: Date | null;
|
||||
birthPlace: string | null;
|
||||
phone: string | null;
|
||||
mobile: string | null;
|
||||
taxNumber: string | null;
|
||||
businessRegistrationPath: string | null;
|
||||
commercialRegisterPath: string | null;
|
||||
commercialRegisterNumber: string | null;
|
||||
privacyPolicyPath: string | null;
|
||||
notes: string | null;
|
||||
portalEnabled: boolean;
|
||||
portalPasswordHash: string | null;
|
||||
portalPasswordEncrypted: string | null;
|
||||
portalLastLogin: Date | null;
|
||||
}>;
|
||||
export declare function getCustomerAddresses(customerId: number): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.AddressType;
|
||||
isDefault: boolean;
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country: string;
|
||||
}[]>;
|
||||
export declare function createAddress(customerId: number, data: {
|
||||
type: 'DELIVERY_RESIDENCE' | 'BILLING';
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country?: string;
|
||||
isDefault?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.AddressType;
|
||||
isDefault: boolean;
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country: string;
|
||||
}>;
|
||||
export declare function updateAddress(id: number, data: {
|
||||
type?: 'DELIVERY_RESIDENCE' | 'BILLING';
|
||||
street?: string;
|
||||
houseNumber?: string;
|
||||
postalCode?: string;
|
||||
city?: string;
|
||||
country?: string;
|
||||
isDefault?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.AddressType;
|
||||
isDefault: boolean;
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country: string;
|
||||
}>;
|
||||
export declare function deleteAddress(id: number): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.AddressType;
|
||||
isDefault: boolean;
|
||||
street: string;
|
||||
houseNumber: string;
|
||||
postalCode: string;
|
||||
city: string;
|
||||
country: string;
|
||||
}>;
|
||||
export declare function getCustomerBankCards(customerId: number, showInactive?: boolean): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
accountHolder: string;
|
||||
iban: string;
|
||||
bic: string | null;
|
||||
bankName: string | null;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
}[]>;
|
||||
export declare function createBankCard(customerId: number, data: {
|
||||
accountHolder: string;
|
||||
iban: string;
|
||||
bic?: string;
|
||||
bankName?: string;
|
||||
expiryDate?: Date;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
accountHolder: string;
|
||||
iban: string;
|
||||
bic: string | null;
|
||||
bankName: string | null;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
}>;
|
||||
export declare function updateBankCard(id: number, data: {
|
||||
accountHolder?: string;
|
||||
iban?: string;
|
||||
bic?: string;
|
||||
bankName?: string;
|
||||
expiryDate?: Date;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
accountHolder: string;
|
||||
iban: string;
|
||||
bic: string | null;
|
||||
bankName: string | null;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
}>;
|
||||
export declare function deleteBankCard(id: number): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
accountHolder: string;
|
||||
iban: string;
|
||||
bic: string | null;
|
||||
bankName: string | null;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
}>;
|
||||
export declare function getCustomerDocuments(customerId: number, showInactive?: boolean): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.DocumentType;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
documentNumber: string;
|
||||
issuingAuthority: string | null;
|
||||
issueDate: Date | null;
|
||||
licenseClasses: string | null;
|
||||
licenseIssueDate: Date | null;
|
||||
}[]>;
|
||||
export declare function createDocument(customerId: number, data: {
|
||||
type: 'ID_CARD' | 'PASSPORT' | 'DRIVERS_LICENSE' | 'OTHER';
|
||||
documentNumber: string;
|
||||
issuingAuthority?: string;
|
||||
issueDate?: Date;
|
||||
expiryDate?: Date;
|
||||
licenseClasses?: string;
|
||||
licenseIssueDate?: Date;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.DocumentType;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
documentNumber: string;
|
||||
issuingAuthority: string | null;
|
||||
issueDate: Date | null;
|
||||
licenseClasses: string | null;
|
||||
licenseIssueDate: Date | null;
|
||||
}>;
|
||||
export declare function updateDocument(id: number, data: {
|
||||
type?: 'ID_CARD' | 'PASSPORT' | 'DRIVERS_LICENSE' | 'OTHER';
|
||||
documentNumber?: string;
|
||||
issuingAuthority?: string;
|
||||
issueDate?: Date;
|
||||
expiryDate?: Date;
|
||||
licenseClasses?: string;
|
||||
licenseIssueDate?: Date;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.DocumentType;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
documentNumber: string;
|
||||
issuingAuthority: string | null;
|
||||
issueDate: Date | null;
|
||||
licenseClasses: string | null;
|
||||
licenseIssueDate: Date | null;
|
||||
}>;
|
||||
export declare function deleteDocument(id: number): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.DocumentType;
|
||||
expiryDate: Date | null;
|
||||
documentPath: string | null;
|
||||
documentNumber: string;
|
||||
issuingAuthority: string | null;
|
||||
issueDate: Date | null;
|
||||
licenseClasses: string | null;
|
||||
licenseIssueDate: Date | null;
|
||||
}>;
|
||||
export declare function getCustomerMeters(customerId: number, showInactive?: boolean): Promise<({
|
||||
readings: {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
notes: string | null;
|
||||
readingDate: Date;
|
||||
value: number;
|
||||
unit: string;
|
||||
meterId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.MeterType;
|
||||
meterNumber: string;
|
||||
location: string | null;
|
||||
})[]>;
|
||||
export declare function createMeter(customerId: number, data: {
|
||||
meterNumber: string;
|
||||
type: 'ELECTRICITY' | 'GAS';
|
||||
location?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.MeterType;
|
||||
meterNumber: string;
|
||||
location: string | null;
|
||||
}>;
|
||||
export declare function updateMeter(id: number, data: {
|
||||
meterNumber?: string;
|
||||
type?: 'ELECTRICITY' | 'GAS';
|
||||
location?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.MeterType;
|
||||
meterNumber: string;
|
||||
location: string | null;
|
||||
}>;
|
||||
export declare function deleteMeter(id: number): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
type: import(".prisma/client").$Enums.MeterType;
|
||||
meterNumber: string;
|
||||
location: string | null;
|
||||
}>;
|
||||
export declare function addMeterReading(meterId: number, data: {
|
||||
readingDate: Date;
|
||||
value: number;
|
||||
unit?: string;
|
||||
notes?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
notes: string | null;
|
||||
readingDate: Date;
|
||||
value: number;
|
||||
unit: string;
|
||||
meterId: number;
|
||||
}>;
|
||||
export declare function getMeterReadings(meterId: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
notes: string | null;
|
||||
readingDate: Date;
|
||||
value: number;
|
||||
unit: string;
|
||||
meterId: number;
|
||||
}[]>;
|
||||
export declare function updateMeterReading(meterId: number, readingId: number, data: {
|
||||
readingDate?: Date;
|
||||
value?: number;
|
||||
unit?: string;
|
||||
notes?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
notes: string | null;
|
||||
readingDate: Date;
|
||||
value: number;
|
||||
unit: string;
|
||||
meterId: number;
|
||||
}>;
|
||||
export declare function deleteMeterReading(meterId: number, readingId: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
notes: string | null;
|
||||
readingDate: Date;
|
||||
value: number;
|
||||
unit: string;
|
||||
meterId: number;
|
||||
}>;
|
||||
export declare function updatePortalSettings(customerId: number, data: {
|
||||
portalEnabled?: boolean;
|
||||
portalEmail?: string | null;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
portalEmail: string | null;
|
||||
portalEnabled: boolean;
|
||||
portalLastLogin: Date | null;
|
||||
}>;
|
||||
export declare function getPortalSettings(customerId: number): Promise<{
|
||||
id: number;
|
||||
portalEmail: string | null;
|
||||
portalEnabled: boolean;
|
||||
portalPasswordHash: string | null;
|
||||
portalLastLogin: Date | null;
|
||||
} | null>;
|
||||
export declare function getCustomerRepresentatives(customerId: number): Promise<({
|
||||
customer: {
|
||||
id: number;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
customerNumber: string;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
companyName: string | null;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
representativeId: number;
|
||||
})[]>;
|
||||
export declare function getRepresentedByList(customerId: number): Promise<({
|
||||
representative: {
|
||||
id: number;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
customerNumber: string;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
companyName: string | null;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
representativeId: number;
|
||||
})[]>;
|
||||
export declare function addRepresentative(customerId: number, // Der Kunde, dessen Verträge eingesehen werden dürfen
|
||||
representativeId: number, // Der Kunde, der einsehen darf
|
||||
notes?: string): Promise<{
|
||||
representative: {
|
||||
id: number;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
customerNumber: string;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
companyName: string | null;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
representativeId: number;
|
||||
}>;
|
||||
export declare function removeRepresentative(customerId: number, representativeId: number): Promise<{
|
||||
id: number;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
representativeId: number;
|
||||
}>;
|
||||
export declare function searchCustomersForRepresentative(search: string, excludeCustomerId: number): Promise<{
|
||||
id: number;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
customerNumber: string;
|
||||
type: import(".prisma/client").$Enums.CustomerType;
|
||||
companyName: string | null;
|
||||
}[]>;
|
||||
//# sourceMappingURL=customer.service.d.ts.map
|
||||
File diff suppressed because one or more lines are too long
+512
@@ -0,0 +1,512 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllCustomers = getAllCustomers;
|
||||
exports.getCustomerById = getCustomerById;
|
||||
exports.getCustomersByIds = getCustomersByIds;
|
||||
exports.createCustomer = createCustomer;
|
||||
exports.updateCustomer = updateCustomer;
|
||||
exports.deleteCustomer = deleteCustomer;
|
||||
exports.getCustomerAddresses = getCustomerAddresses;
|
||||
exports.createAddress = createAddress;
|
||||
exports.updateAddress = updateAddress;
|
||||
exports.deleteAddress = deleteAddress;
|
||||
exports.getCustomerBankCards = getCustomerBankCards;
|
||||
exports.createBankCard = createBankCard;
|
||||
exports.updateBankCard = updateBankCard;
|
||||
exports.deleteBankCard = deleteBankCard;
|
||||
exports.getCustomerDocuments = getCustomerDocuments;
|
||||
exports.createDocument = createDocument;
|
||||
exports.updateDocument = updateDocument;
|
||||
exports.deleteDocument = deleteDocument;
|
||||
exports.getCustomerMeters = getCustomerMeters;
|
||||
exports.createMeter = createMeter;
|
||||
exports.updateMeter = updateMeter;
|
||||
exports.deleteMeter = deleteMeter;
|
||||
exports.addMeterReading = addMeterReading;
|
||||
exports.getMeterReadings = getMeterReadings;
|
||||
exports.updateMeterReading = updateMeterReading;
|
||||
exports.deleteMeterReading = deleteMeterReading;
|
||||
exports.updatePortalSettings = updatePortalSettings;
|
||||
exports.getPortalSettings = getPortalSettings;
|
||||
exports.getCustomerRepresentatives = getCustomerRepresentatives;
|
||||
exports.getRepresentedByList = getRepresentedByList;
|
||||
exports.addRepresentative = addRepresentative;
|
||||
exports.removeRepresentative = removeRepresentative;
|
||||
exports.searchCustomersForRepresentative = searchCustomersForRepresentative;
|
||||
const client_1 = require("@prisma/client");
|
||||
const helpers_js_1 = require("../utils/helpers.js");
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const path_1 = __importDefault(require("path"));
|
||||
const prisma = new client_1.PrismaClient();
|
||||
// Helper zum Löschen von Dateien
|
||||
function deleteFileIfExists(filePath) {
|
||||
if (!filePath)
|
||||
return;
|
||||
const absolutePath = path_1.default.join(process.cwd(), filePath);
|
||||
if (fs_1.default.existsSync(absolutePath)) {
|
||||
try {
|
||||
fs_1.default.unlinkSync(absolutePath);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Fehler beim Löschen der Datei:', absolutePath, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
async function getAllCustomers(filters) {
|
||||
const { search, type, page = 1, limit = 20 } = filters;
|
||||
const { skip, take } = (0, helpers_js_1.paginate)(page, limit);
|
||||
const where = {};
|
||||
if (type) {
|
||||
where.type = type;
|
||||
}
|
||||
if (search) {
|
||||
where.OR = [
|
||||
{ firstName: { contains: search } },
|
||||
{ lastName: { contains: search } },
|
||||
{ companyName: { contains: search } },
|
||||
{ email: { contains: search } },
|
||||
{ customerNumber: { contains: search } },
|
||||
];
|
||||
}
|
||||
const [customers, total] = await Promise.all([
|
||||
prisma.customer.findMany({
|
||||
where,
|
||||
skip,
|
||||
take,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
include: {
|
||||
addresses: { where: { isDefault: true }, take: 1 },
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.customer.count({ where }),
|
||||
]);
|
||||
return {
|
||||
customers,
|
||||
pagination: (0, helpers_js_1.buildPaginationResponse)(page, limit, total),
|
||||
};
|
||||
}
|
||||
async function getCustomerById(id) {
|
||||
return prisma.customer.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
addresses: true,
|
||||
bankCards: { orderBy: { isActive: 'desc' } },
|
||||
identityDocuments: { orderBy: { isActive: 'desc' } },
|
||||
meters: {
|
||||
orderBy: { isActive: 'desc' },
|
||||
include: {
|
||||
readings: {
|
||||
orderBy: { readingDate: 'desc' },
|
||||
},
|
||||
},
|
||||
},
|
||||
stressfreiEmails: { orderBy: { isActive: 'desc' } },
|
||||
contracts: {
|
||||
orderBy: [{ startDate: 'desc' }, { createdAt: 'desc' }],
|
||||
include: {
|
||||
address: true,
|
||||
salesPlatform: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function getCustomersByIds(ids) {
|
||||
return prisma.customer.findMany({
|
||||
where: { id: { in: ids } },
|
||||
select: {
|
||||
id: true,
|
||||
portalEmail: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function createCustomer(data) {
|
||||
return prisma.customer.create({
|
||||
data: {
|
||||
...data,
|
||||
customerNumber: (0, helpers_js_1.generateCustomerNumber)(),
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateCustomer(id, data) {
|
||||
return prisma.customer.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteCustomer(id) {
|
||||
// Vor dem Löschen: Alle Dokumente (Dateien) des Kunden löschen
|
||||
const customer = await prisma.customer.findUnique({
|
||||
where: { id },
|
||||
select: { businessRegistrationPath: true, commercialRegisterPath: true, privacyPolicyPath: true },
|
||||
});
|
||||
const bankCards = await prisma.bankCard.findMany({
|
||||
where: { customerId: id },
|
||||
select: { documentPath: true },
|
||||
});
|
||||
const identityDocs = await prisma.identityDocument.findMany({
|
||||
where: { customerId: id },
|
||||
select: { documentPath: true },
|
||||
});
|
||||
// Kundendokumente löschen
|
||||
if (customer) {
|
||||
deleteFileIfExists(customer.businessRegistrationPath);
|
||||
deleteFileIfExists(customer.commercialRegisterPath);
|
||||
deleteFileIfExists(customer.privacyPolicyPath);
|
||||
}
|
||||
// Bankkarten- und Ausweisdokumente löschen
|
||||
for (const card of bankCards) {
|
||||
deleteFileIfExists(card.documentPath);
|
||||
}
|
||||
for (const doc of identityDocs) {
|
||||
deleteFileIfExists(doc.documentPath);
|
||||
}
|
||||
// Jetzt DB-Eintrag löschen (Cascade löscht die verknüpften Einträge)
|
||||
return prisma.customer.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
// Address operations
|
||||
async function getCustomerAddresses(customerId) {
|
||||
return prisma.address.findMany({
|
||||
where: { customerId },
|
||||
orderBy: [{ isDefault: 'desc' }, { createdAt: 'desc' }],
|
||||
});
|
||||
}
|
||||
async function createAddress(customerId, data) {
|
||||
// If this is set as default, unset other defaults of same type
|
||||
if (data.isDefault) {
|
||||
await prisma.address.updateMany({
|
||||
where: { customerId, type: data.type },
|
||||
data: { isDefault: false },
|
||||
});
|
||||
}
|
||||
return prisma.address.create({
|
||||
data: {
|
||||
customerId,
|
||||
...data,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateAddress(id, data) {
|
||||
const address = await prisma.address.findUnique({ where: { id } });
|
||||
if (!address)
|
||||
throw new Error('Adresse nicht gefunden');
|
||||
if (data.isDefault) {
|
||||
await prisma.address.updateMany({
|
||||
where: {
|
||||
customerId: address.customerId,
|
||||
type: data.type || address.type,
|
||||
id: { not: id },
|
||||
},
|
||||
data: { isDefault: false },
|
||||
});
|
||||
}
|
||||
return prisma.address.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteAddress(id) {
|
||||
return prisma.address.delete({ where: { id } });
|
||||
}
|
||||
// Bank card operations
|
||||
async function getCustomerBankCards(customerId, showInactive = false) {
|
||||
const where = { customerId };
|
||||
if (!showInactive) {
|
||||
where.isActive = true;
|
||||
}
|
||||
return prisma.bankCard.findMany({
|
||||
where,
|
||||
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
|
||||
});
|
||||
}
|
||||
async function createBankCard(customerId, data) {
|
||||
return prisma.bankCard.create({
|
||||
data: {
|
||||
customerId,
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateBankCard(id, data) {
|
||||
return prisma.bankCard.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteBankCard(id) {
|
||||
// Erst Datei-Pfad holen, dann Datei löschen, dann DB-Eintrag löschen
|
||||
const bankCard = await prisma.bankCard.findUnique({ where: { id } });
|
||||
if (bankCard?.documentPath) {
|
||||
deleteFileIfExists(bankCard.documentPath);
|
||||
}
|
||||
return prisma.bankCard.delete({ where: { id } });
|
||||
}
|
||||
// Identity document operations
|
||||
async function getCustomerDocuments(customerId, showInactive = false) {
|
||||
const where = { customerId };
|
||||
if (!showInactive) {
|
||||
where.isActive = true;
|
||||
}
|
||||
return prisma.identityDocument.findMany({
|
||||
where,
|
||||
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
|
||||
});
|
||||
}
|
||||
async function createDocument(customerId, data) {
|
||||
return prisma.identityDocument.create({
|
||||
data: {
|
||||
customerId,
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateDocument(id, data) {
|
||||
return prisma.identityDocument.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteDocument(id) {
|
||||
// Erst Datei-Pfad holen, dann Datei löschen, dann DB-Eintrag löschen
|
||||
const document = await prisma.identityDocument.findUnique({ where: { id } });
|
||||
if (document?.documentPath) {
|
||||
deleteFileIfExists(document.documentPath);
|
||||
}
|
||||
return prisma.identityDocument.delete({ where: { id } });
|
||||
}
|
||||
// Meter operations
|
||||
async function getCustomerMeters(customerId, showInactive = false) {
|
||||
const where = { customerId };
|
||||
if (!showInactive) {
|
||||
where.isActive = true;
|
||||
}
|
||||
return prisma.meter.findMany({
|
||||
where,
|
||||
include: {
|
||||
readings: {
|
||||
orderBy: { readingDate: 'desc' },
|
||||
take: 5,
|
||||
},
|
||||
},
|
||||
orderBy: [{ isActive: 'desc' }, { createdAt: 'desc' }],
|
||||
});
|
||||
}
|
||||
async function createMeter(customerId, data) {
|
||||
return prisma.meter.create({
|
||||
data: {
|
||||
customerId,
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateMeter(id, data) {
|
||||
return prisma.meter.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteMeter(id) {
|
||||
return prisma.meter.delete({ where: { id } });
|
||||
}
|
||||
async function addMeterReading(meterId, data) {
|
||||
return prisma.meterReading.create({
|
||||
data: {
|
||||
meterId,
|
||||
...data,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function getMeterReadings(meterId) {
|
||||
return prisma.meterReading.findMany({
|
||||
where: { meterId },
|
||||
orderBy: { readingDate: 'desc' },
|
||||
});
|
||||
}
|
||||
async function updateMeterReading(meterId, readingId, data) {
|
||||
// Verify the reading belongs to the meter
|
||||
const reading = await prisma.meterReading.findFirst({
|
||||
where: { id: readingId, meterId },
|
||||
});
|
||||
if (!reading) {
|
||||
throw new Error('Zählerstand nicht gefunden');
|
||||
}
|
||||
return prisma.meterReading.update({
|
||||
where: { id: readingId },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteMeterReading(meterId, readingId) {
|
||||
// Verify the reading belongs to the meter
|
||||
const reading = await prisma.meterReading.findFirst({
|
||||
where: { id: readingId, meterId },
|
||||
});
|
||||
if (!reading) {
|
||||
throw new Error('Zählerstand nicht gefunden');
|
||||
}
|
||||
return prisma.meterReading.delete({
|
||||
where: { id: readingId },
|
||||
});
|
||||
}
|
||||
// ==================== PORTAL SETTINGS ====================
|
||||
async function updatePortalSettings(customerId, data) {
|
||||
// Wenn Portal deaktiviert wird, Passwort-Hash nicht löschen (für spätere Reaktivierung)
|
||||
return prisma.customer.update({
|
||||
where: { id: customerId },
|
||||
data: {
|
||||
portalEnabled: data.portalEnabled,
|
||||
portalEmail: data.portalEmail,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
portalEnabled: true,
|
||||
portalEmail: true,
|
||||
portalLastLogin: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function getPortalSettings(customerId) {
|
||||
return prisma.customer.findUnique({
|
||||
where: { id: customerId },
|
||||
select: {
|
||||
id: true,
|
||||
portalEnabled: true,
|
||||
portalEmail: true,
|
||||
portalLastLogin: true,
|
||||
portalPasswordHash: true, // Nur um zu prüfen ob Passwort gesetzt (wird als boolean zurückgegeben)
|
||||
},
|
||||
});
|
||||
}
|
||||
// ==================== REPRESENTATIVE MANAGEMENT ====================
|
||||
async function getCustomerRepresentatives(customerId) {
|
||||
// Holt alle Kunden, die der angegebene Kunde vertreten kann (dieser ist der Vertreter)
|
||||
return prisma.customerRepresentative.findMany({
|
||||
where: { representativeId: customerId, isActive: true },
|
||||
include: {
|
||||
customer: {
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
}
|
||||
async function getRepresentedByList(customerId) {
|
||||
// Holt alle Kunden, die den angegebenen Kunden vertreten können
|
||||
return prisma.customerRepresentative.findMany({
|
||||
where: { customerId: customerId, isActive: true },
|
||||
include: {
|
||||
representative: {
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
}
|
||||
async function addRepresentative(customerId, // Der Kunde, dessen Verträge eingesehen werden dürfen
|
||||
representativeId, // Der Kunde, der einsehen darf
|
||||
notes) {
|
||||
// Prüfen, ob beide Kunden existieren
|
||||
const [customer, representative] = await Promise.all([
|
||||
prisma.customer.findUnique({ where: { id: customerId } }),
|
||||
prisma.customer.findUnique({ where: { id: representativeId } }),
|
||||
]);
|
||||
if (!customer) {
|
||||
throw new Error('Kunde nicht gefunden');
|
||||
}
|
||||
if (!representative) {
|
||||
throw new Error('Vertreter-Kunde nicht gefunden');
|
||||
}
|
||||
if (customerId === representativeId) {
|
||||
throw new Error('Ein Kunde kann sich nicht selbst vertreten');
|
||||
}
|
||||
// Prüfen ob der Vertreter ein Portal-Konto hat
|
||||
if (!representative.portalEnabled) {
|
||||
throw new Error('Der Vertreter-Kunde muss ein aktiviertes Portal-Konto haben');
|
||||
}
|
||||
return prisma.customerRepresentative.upsert({
|
||||
where: {
|
||||
customerId_representativeId: { customerId, representativeId },
|
||||
},
|
||||
create: {
|
||||
customerId,
|
||||
representativeId,
|
||||
notes,
|
||||
isActive: true,
|
||||
},
|
||||
update: {
|
||||
isActive: true,
|
||||
notes,
|
||||
},
|
||||
include: {
|
||||
representative: {
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function removeRepresentative(customerId, representativeId) {
|
||||
// Anstatt zu löschen, setzen wir isActive auf false
|
||||
return prisma.customerRepresentative.update({
|
||||
where: {
|
||||
customerId_representativeId: { customerId, representativeId },
|
||||
},
|
||||
data: { isActive: false },
|
||||
});
|
||||
}
|
||||
async function searchCustomersForRepresentative(search, excludeCustomerId) {
|
||||
// Sucht Kunden, die als Vertreter hinzugefügt werden können
|
||||
// Nur Kunden mit aktiviertem Portal
|
||||
return prisma.customer.findMany({
|
||||
where: {
|
||||
id: { not: excludeCustomerId },
|
||||
portalEnabled: true,
|
||||
OR: [
|
||||
{ firstName: { contains: search } },
|
||||
{ lastName: { contains: search } },
|
||||
{ companyName: { contains: search } },
|
||||
{ customerNumber: { contains: search } },
|
||||
],
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
customerNumber: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
companyName: true,
|
||||
type: true,
|
||||
},
|
||||
take: 10,
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=customer.service.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,135 @@
|
||||
import { EmailExistsResult, EmailOperationResult } from './types.js';
|
||||
export declare function getAllProviderConfigs(): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}[]>;
|
||||
export declare function getProviderConfigById(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
} | null>;
|
||||
export declare function getDefaultProviderConfig(): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
} | null>;
|
||||
export declare function getActiveProviderConfig(): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
} | null>;
|
||||
export interface CreateProviderConfigData {
|
||||
name: string;
|
||||
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
||||
apiUrl: string;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain: string;
|
||||
defaultForwardEmail?: string;
|
||||
isActive?: boolean;
|
||||
isDefault?: boolean;
|
||||
}
|
||||
export declare function createProviderConfig(data: CreateProviderConfigData): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}>;
|
||||
export declare function updateProviderConfig(id: number, data: Partial<CreateProviderConfigData>): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}>;
|
||||
export declare function deleteProviderConfig(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
type: import(".prisma/client").$Enums.EmailProviderType;
|
||||
isDefault: boolean;
|
||||
apiUrl: string;
|
||||
apiKey: string | null;
|
||||
username: string | null;
|
||||
passwordEncrypted: string | null;
|
||||
domain: string;
|
||||
defaultForwardEmail: string | null;
|
||||
}>;
|
||||
export declare function checkEmailExists(localPart: string): Promise<EmailExistsResult>;
|
||||
export declare function provisionEmail(localPart: string, customerEmail: string): Promise<EmailOperationResult>;
|
||||
export declare function deprovisionEmail(localPart: string): Promise<EmailOperationResult>;
|
||||
export declare function renameProvisionedEmail(oldLocalPart: string, newLocalPart: string): Promise<EmailOperationResult>;
|
||||
export declare function getProviderDomain(): Promise<string | null>;
|
||||
export declare function testProviderConnection(options?: {
|
||||
id?: number;
|
||||
testData?: {
|
||||
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
||||
apiUrl: string;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain: string;
|
||||
};
|
||||
}): Promise<EmailOperationResult>;
|
||||
//# sourceMappingURL=emailProviderService.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"emailProviderService.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/emailProviderService.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,iBAAiB,EACjB,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAuBpB,wBAAsB,qBAAqB;;;;;;;;;;;;;;KAI1C;AAED,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;UAIrD;AAED,wBAAsB,wBAAwB;;;;;;;;;;;;;;UAI7C;AAED,wBAAsB,uBAAuB;;;;;;;;;;;;;;UAQ5C;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,wBAAwB;;;;;;;;;;;;;;GA2BxE;AAED,wBAAsB,oBAAoB,CACxC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,OAAO,CAAC,wBAAwB,CAAC;;;;;;;;;;;;;;GAsCxC;AAED,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;GAIpD;AAwCD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAQpF;AAGD,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,oBAAoB,CAAC,CAoC/B;AAGD,wBAAsB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAWvF;AAGD,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,CAAC,CAW/B;AAGD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGhE;AA8DD,wBAAsB,sBAAsB,CAAC,OAAO,CAAC,EAAE;IACrD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;QACzC,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA6BhC"}
|
||||
@@ -0,0 +1,323 @@
|
||||
"use strict";
|
||||
// ==================== EMAIL PROVIDER SERVICE ====================
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllProviderConfigs = getAllProviderConfigs;
|
||||
exports.getProviderConfigById = getProviderConfigById;
|
||||
exports.getDefaultProviderConfig = getDefaultProviderConfig;
|
||||
exports.getActiveProviderConfig = getActiveProviderConfig;
|
||||
exports.createProviderConfig = createProviderConfig;
|
||||
exports.updateProviderConfig = updateProviderConfig;
|
||||
exports.deleteProviderConfig = deleteProviderConfig;
|
||||
exports.checkEmailExists = checkEmailExists;
|
||||
exports.provisionEmail = provisionEmail;
|
||||
exports.deprovisionEmail = deprovisionEmail;
|
||||
exports.renameProvisionedEmail = renameProvisionedEmail;
|
||||
exports.getProviderDomain = getProviderDomain;
|
||||
exports.testProviderConnection = testProviderConnection;
|
||||
const client_1 = require("@prisma/client");
|
||||
const encryption_js_1 = require("../../utils/encryption.js");
|
||||
const pleskProvider_js_1 = require("./pleskProvider.js");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
// Factory-Funktion um den richtigen Provider zu erstellen
|
||||
function createProvider(config) {
|
||||
switch (config.type) {
|
||||
case 'PLESK':
|
||||
return new pleskProvider_js_1.PleskEmailProvider(config);
|
||||
case 'CPANEL':
|
||||
// TODO: cPanel Provider implementieren
|
||||
throw new Error('cPanel Provider noch nicht implementiert');
|
||||
case 'DIRECTADMIN':
|
||||
// TODO: DirectAdmin Provider implementieren
|
||||
throw new Error('DirectAdmin Provider noch nicht implementiert');
|
||||
default:
|
||||
throw new Error(`Unbekannter Provider-Typ: ${config.type}`);
|
||||
}
|
||||
}
|
||||
// ==================== CONFIG CRUD ====================
|
||||
async function getAllProviderConfigs() {
|
||||
return prisma.emailProviderConfig.findMany({
|
||||
orderBy: [{ isDefault: 'desc' }, { name: 'asc' }],
|
||||
});
|
||||
}
|
||||
async function getProviderConfigById(id) {
|
||||
return prisma.emailProviderConfig.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
async function getDefaultProviderConfig() {
|
||||
return prisma.emailProviderConfig.findFirst({
|
||||
where: { isActive: true, isDefault: true },
|
||||
});
|
||||
}
|
||||
async function getActiveProviderConfig() {
|
||||
// Erst Default-Provider versuchen, dann irgendeinen aktiven
|
||||
const defaultProvider = await getDefaultProviderConfig();
|
||||
if (defaultProvider)
|
||||
return defaultProvider;
|
||||
return prisma.emailProviderConfig.findFirst({
|
||||
where: { isActive: true },
|
||||
});
|
||||
}
|
||||
async function createProviderConfig(data) {
|
||||
// Falls isDefault=true, alle anderen auf false setzen
|
||||
if (data.isDefault) {
|
||||
await prisma.emailProviderConfig.updateMany({
|
||||
where: { isDefault: true },
|
||||
data: { isDefault: false },
|
||||
});
|
||||
}
|
||||
// Passwort verschlüsseln falls vorhanden
|
||||
const { encrypt } = await import('../../utils/encryption.js');
|
||||
const passwordEncrypted = data.password ? encrypt(data.password) : null;
|
||||
return prisma.emailProviderConfig.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
type: data.type,
|
||||
apiUrl: data.apiUrl,
|
||||
apiKey: data.apiKey || null,
|
||||
username: data.username || null,
|
||||
passwordEncrypted,
|
||||
domain: data.domain,
|
||||
defaultForwardEmail: data.defaultForwardEmail || null,
|
||||
isActive: data.isActive ?? true,
|
||||
isDefault: data.isDefault ?? false,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateProviderConfig(id, data) {
|
||||
// Falls isDefault=true, alle anderen auf false setzen
|
||||
if (data.isDefault) {
|
||||
await prisma.emailProviderConfig.updateMany({
|
||||
where: { isDefault: true, id: { not: id } },
|
||||
data: { isDefault: false },
|
||||
});
|
||||
}
|
||||
const updateData = {};
|
||||
if (data.name !== undefined)
|
||||
updateData.name = data.name;
|
||||
if (data.type !== undefined)
|
||||
updateData.type = data.type;
|
||||
if (data.apiUrl !== undefined)
|
||||
updateData.apiUrl = data.apiUrl;
|
||||
if (data.apiKey !== undefined)
|
||||
updateData.apiKey = data.apiKey || null;
|
||||
if (data.username !== undefined)
|
||||
updateData.username = data.username || null;
|
||||
if (data.domain !== undefined)
|
||||
updateData.domain = data.domain;
|
||||
if (data.defaultForwardEmail !== undefined)
|
||||
updateData.defaultForwardEmail = data.defaultForwardEmail || null;
|
||||
if (data.isActive !== undefined)
|
||||
updateData.isActive = data.isActive;
|
||||
if (data.isDefault !== undefined)
|
||||
updateData.isDefault = data.isDefault;
|
||||
// Passwort-Logik:
|
||||
// - Wenn neues Passwort übergeben → verschlüsseln und speichern
|
||||
// - Wenn Benutzername gelöscht wird → Passwort auch löschen (gehören zusammen)
|
||||
if (data.password) {
|
||||
const { encrypt } = await import('../../utils/encryption.js');
|
||||
updateData.passwordEncrypted = encrypt(data.password);
|
||||
}
|
||||
else if (data.username !== undefined && !data.username) {
|
||||
// Benutzername wird gelöscht → Passwort auch löschen
|
||||
updateData.passwordEncrypted = null;
|
||||
}
|
||||
return prisma.emailProviderConfig.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
});
|
||||
}
|
||||
async function deleteProviderConfig(id) {
|
||||
return prisma.emailProviderConfig.delete({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
// ==================== EMAIL OPERATIONS ====================
|
||||
// Provider-Instanz aus DB-Config erstellen
|
||||
async function getProviderInstance() {
|
||||
const dbConfig = await getActiveProviderConfig();
|
||||
if (!dbConfig) {
|
||||
throw new Error('Kein aktiver Email-Provider konfiguriert');
|
||||
}
|
||||
// Passwort entschlüsseln
|
||||
let password;
|
||||
if (dbConfig.passwordEncrypted) {
|
||||
try {
|
||||
password = (0, encryption_js_1.decrypt)(dbConfig.passwordEncrypted);
|
||||
}
|
||||
catch {
|
||||
console.error('Konnte Passwort nicht entschlüsseln');
|
||||
}
|
||||
}
|
||||
const config = {
|
||||
id: dbConfig.id,
|
||||
name: dbConfig.name,
|
||||
type: dbConfig.type,
|
||||
apiUrl: dbConfig.apiUrl,
|
||||
apiKey: dbConfig.apiKey || undefined,
|
||||
username: dbConfig.username || undefined,
|
||||
password,
|
||||
domain: dbConfig.domain,
|
||||
defaultForwardEmail: dbConfig.defaultForwardEmail || undefined,
|
||||
isActive: dbConfig.isActive,
|
||||
isDefault: dbConfig.isDefault,
|
||||
};
|
||||
return createProvider(config);
|
||||
}
|
||||
// Prüfen ob eine E-Mail existiert
|
||||
async function checkEmailExists(localPart) {
|
||||
try {
|
||||
const provider = await getProviderInstance();
|
||||
return provider.emailExists(localPart);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('checkEmailExists error:', error);
|
||||
return { exists: false };
|
||||
}
|
||||
}
|
||||
// E-Mail erstellen mit Weiterleitungen
|
||||
async function provisionEmail(localPart, customerEmail) {
|
||||
try {
|
||||
const provider = await getProviderInstance();
|
||||
const config = await getActiveProviderConfig();
|
||||
// Weiterleitungsziele zusammenstellen
|
||||
const forwardTargets = [customerEmail];
|
||||
// Unsere eigene Weiterleitungsadresse hinzufügen falls konfiguriert
|
||||
if (config?.defaultForwardEmail) {
|
||||
forwardTargets.push(config.defaultForwardEmail);
|
||||
}
|
||||
// Prüfen ob existiert
|
||||
const exists = await provider.emailExists(localPart);
|
||||
if (exists.exists) {
|
||||
return {
|
||||
success: true,
|
||||
message: `E-Mail ${exists.email} existiert bereits`,
|
||||
};
|
||||
}
|
||||
// Erstellen
|
||||
const result = await provider.createEmail({
|
||||
localPart,
|
||||
forwardTargets,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
// E-Mail löschen
|
||||
async function deprovisionEmail(localPart) {
|
||||
try {
|
||||
const provider = await getProviderInstance();
|
||||
return provider.deleteEmail(localPart);
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
// E-Mail umbenennen
|
||||
async function renameProvisionedEmail(oldLocalPart, newLocalPart) {
|
||||
try {
|
||||
const provider = await getProviderInstance();
|
||||
return provider.renameEmail({ oldLocalPart, newLocalPart });
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
// Domain aus aktivem Provider holen
|
||||
async function getProviderDomain() {
|
||||
const config = await getActiveProviderConfig();
|
||||
return config?.domain || null;
|
||||
}
|
||||
// Provider-Instanz aus übergebener Config erstellen (für Tests mit ungespeicherten Daten)
|
||||
function createProviderFromFormData(data) {
|
||||
const config = {
|
||||
id: 0,
|
||||
name: 'Test',
|
||||
type: data.type,
|
||||
apiUrl: data.apiUrl,
|
||||
apiKey: data.apiKey,
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
domain: data.domain,
|
||||
isActive: true,
|
||||
isDefault: false,
|
||||
};
|
||||
return createProvider(config);
|
||||
}
|
||||
// Provider-Instanz aus DB-Config per ID erstellen
|
||||
async function getProviderInstanceById(id) {
|
||||
const dbConfig = await getProviderConfigById(id);
|
||||
if (!dbConfig) {
|
||||
throw new Error('Email-Provider nicht gefunden');
|
||||
}
|
||||
// Passwort entschlüsseln
|
||||
let password;
|
||||
if (dbConfig.passwordEncrypted) {
|
||||
try {
|
||||
password = (0, encryption_js_1.decrypt)(dbConfig.passwordEncrypted);
|
||||
}
|
||||
catch {
|
||||
console.error('Konnte Passwort nicht entschlüsseln');
|
||||
}
|
||||
}
|
||||
const config = {
|
||||
id: dbConfig.id,
|
||||
name: dbConfig.name,
|
||||
type: dbConfig.type,
|
||||
apiUrl: dbConfig.apiUrl,
|
||||
apiKey: dbConfig.apiKey || undefined,
|
||||
username: dbConfig.username || undefined,
|
||||
password,
|
||||
domain: dbConfig.domain,
|
||||
defaultForwardEmail: dbConfig.defaultForwardEmail || undefined,
|
||||
isActive: dbConfig.isActive,
|
||||
isDefault: dbConfig.isDefault,
|
||||
};
|
||||
return createProvider(config);
|
||||
}
|
||||
// Provider-Verbindung testen (mit ID, Formulardaten oder Default-Provider)
|
||||
async function testProviderConnection(options) {
|
||||
try {
|
||||
let provider;
|
||||
if (options?.testData) {
|
||||
// Mit übergebenen Daten testen (z.B. aus Modal beim Neuanlegen)
|
||||
provider = createProviderFromFormData(options.testData);
|
||||
}
|
||||
else if (options?.id) {
|
||||
// Gespeicherten Provider per ID testen
|
||||
provider = await getProviderInstanceById(options.id);
|
||||
}
|
||||
else {
|
||||
// Default-Provider testen
|
||||
provider = await getProviderInstance();
|
||||
}
|
||||
// Expliziter Verbindungstest (wirft Fehler bei Auth-Problemen)
|
||||
await provider.testConnection();
|
||||
return {
|
||||
success: true,
|
||||
message: 'Verbindung zum Email-Provider erfolgreich',
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
return {
|
||||
success: false,
|
||||
error: errorMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=emailProviderService.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
export * from './types.js';
|
||||
export * from './emailProviderService.js';
|
||||
export { PleskEmailProvider } from './pleskProvider.js';
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAC;AAC3B,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
// ==================== EMAIL PROVIDER EXPORTS ====================
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PleskEmailProvider = void 0;
|
||||
__exportStar(require("./types.js"), exports);
|
||||
__exportStar(require("./emailProviderService.js"), exports);
|
||||
var pleskProvider_js_1 = require("./pleskProvider.js");
|
||||
Object.defineProperty(exports, "PleskEmailProvider", { enumerable: true, get: function () { return pleskProvider_js_1.PleskEmailProvider; } });
|
||||
//# sourceMappingURL=index.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/emailProvider/index.ts"],"names":[],"mappings":";AAAA,mEAAmE;;;;;;;;;;;;;;;;;AAEnE,6CAA2B;AAC3B,4DAA0C;AAC1C,uDAAwD;AAA/C,sHAAA,kBAAkB,OAAA"}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { IEmailProvider, EmailProviderConfig, EmailExistsResult, EmailOperationResult, CreateEmailParams, RenameEmailParams } from './types.js';
|
||||
export declare class PleskEmailProvider implements IEmailProvider {
|
||||
readonly type = "PLESK";
|
||||
private config;
|
||||
constructor(config: EmailProviderConfig);
|
||||
private get baseUrl();
|
||||
private request;
|
||||
testConnection(): Promise<void>;
|
||||
emailExists(localPart: string): Promise<EmailExistsResult>;
|
||||
createEmail(params: CreateEmailParams): Promise<EmailOperationResult>;
|
||||
deleteEmail(localPart: string): Promise<EmailOperationResult>;
|
||||
renameEmail(params: RenameEmailParams): Promise<EmailOperationResult>;
|
||||
updateForwardTargets(localPart: string, targets: string[]): Promise<EmailOperationResult>;
|
||||
}
|
||||
//# sourceMappingURL=pleskProvider.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"pleskProvider.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/pleskProvider.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAiBpB,qBAAa,kBAAmB,YAAW,cAAc;IACvD,QAAQ,CAAC,IAAI,WAAW;IACxB,OAAO,CAAC,MAAM,CAAsB;gBAExB,MAAM,EAAE,mBAAmB;IAKvC,OAAO,KAAK,OAAO,GAGlB;YAGa,OAAO;IAsFf,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB/B,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IA8C1D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAuCrE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAgC7D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA2CrE,oBAAoB,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,oBAAoB,CAAC;CAmCjC"}
|
||||
@@ -0,0 +1,297 @@
|
||||
"use strict";
|
||||
// ==================== PLESK EMAIL PROVIDER ====================
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PleskEmailProvider = void 0;
|
||||
const undici_1 = require("undici");
|
||||
// Undici-Agent der selbstsignierte Zertifikate akzeptiert
|
||||
// Mit Timeouts und Connection-Limits um Probleme zu vermeiden
|
||||
const httpsAgent = new undici_1.Agent({
|
||||
connect: {
|
||||
rejectUnauthorized: false,
|
||||
timeout: 10000, // 10 Sekunden Connect-Timeout
|
||||
},
|
||||
bodyTimeout: 30000, // 30 Sekunden für Response-Body
|
||||
headersTimeout: 30000, // 30 Sekunden für Headers
|
||||
keepAliveTimeout: 1000, // Connections nach 1 Sekunde schließen
|
||||
keepAliveMaxTimeout: 5000, // Maximal 5 Sekunden Keep-Alive
|
||||
connections: 1, // Nur eine Connection gleichzeitig pro Host
|
||||
pipelining: 1, // Kein Pipelining
|
||||
});
|
||||
class PleskEmailProvider {
|
||||
type = 'PLESK';
|
||||
config;
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
// Basis-URL für API-Requests
|
||||
get baseUrl() {
|
||||
// Entferne trailing slash falls vorhanden
|
||||
return this.config.apiUrl.replace(/\/$/, '');
|
||||
}
|
||||
// HTTP-Request an Plesk API senden
|
||||
async request(method, endpoint, data) {
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
};
|
||||
// Authentifizierung: API-Key hat Priorität, sonst Basic Auth
|
||||
if (this.config.apiKey) {
|
||||
// Nur API-Key verwenden (ohne Basic Auth)
|
||||
headers['X-API-Key'] = this.config.apiKey;
|
||||
}
|
||||
else if (this.config.username && this.config.password) {
|
||||
// Basic Auth nur wenn kein API-Key
|
||||
const authHeader = Buffer.from(`${this.config.username}:${this.config.password}`).toString('base64');
|
||||
headers['Authorization'] = `Basic ${authHeader}`;
|
||||
}
|
||||
else {
|
||||
// Keine Authentifizierung vorhanden
|
||||
throw new Error('Keine Zugangsdaten angegeben - bitte API-Key oder Benutzername/Passwort eingeben');
|
||||
}
|
||||
const options = {
|
||||
method,
|
||||
headers,
|
||||
dispatcher: httpsAgent,
|
||||
};
|
||||
if (data && (method === 'POST' || method === 'PUT')) {
|
||||
options.body = JSON.stringify(data);
|
||||
}
|
||||
try {
|
||||
const response = await (0, undici_1.fetch)(url, options);
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Plesk API Fehler: ${response.status} - ${errorText}`);
|
||||
}
|
||||
// Leere Response bei DELETE
|
||||
if (response.status === 204) {
|
||||
return {};
|
||||
}
|
||||
return await response.json();
|
||||
}
|
||||
catch (error) {
|
||||
// Verbesserte Fehlermeldungen für häufige Probleme
|
||||
if (error instanceof Error) {
|
||||
const msg = error.message.toLowerCase();
|
||||
// Netzwerkfehler
|
||||
if (msg.includes('econnrefused')) {
|
||||
throw new Error(`Server nicht erreichbar unter ${this.baseUrl} - Ist der Server gestartet?`);
|
||||
}
|
||||
if (msg.includes('enotfound') || msg.includes('getaddrinfo')) {
|
||||
throw new Error(`Server-Adresse nicht gefunden: ${this.baseUrl} - Bitte URL prüfen`);
|
||||
}
|
||||
if (msg.includes('etimedout') || msg.includes('timeout')) {
|
||||
throw new Error(`Zeitüberschreitung bei Verbindung zu ${this.baseUrl}`);
|
||||
}
|
||||
if (msg.includes('econnreset')) {
|
||||
throw new Error(`Verbindung wurde vom Server abgebrochen`);
|
||||
}
|
||||
// SSL/TLS Fehler
|
||||
if (msg.includes('cert') || msg.includes('ssl') || msg.includes('tls') || msg.includes('unable_to_verify')) {
|
||||
throw new Error(`SSL-Zertifikatsfehler - Selbstsigniertes Zertifikat wird nicht akzeptiert`);
|
||||
}
|
||||
// fetch failed ist meist ein Netzwerk/SSL Problem
|
||||
if (msg.includes('fetch failed')) {
|
||||
throw new Error(`Verbindung fehlgeschlagen zu ${this.baseUrl} - Bitte prüfen: Server erreichbar? HTTPS-Port korrekt?`);
|
||||
}
|
||||
}
|
||||
console.error('Plesk API Request failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async testConnection() {
|
||||
// Versuche Server-Info abzurufen - wirft Fehler bei Auth-Problemen
|
||||
try {
|
||||
await this.request('GET', '/api/v2/server');
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
// Verbesserte Fehlermeldung
|
||||
if (error.message.includes('401')) {
|
||||
throw new Error('Authentifizierung fehlgeschlagen - Benutzername/Passwort oder API-Key prüfen');
|
||||
}
|
||||
if (error.message.includes('403')) {
|
||||
throw new Error('Zugriff verweigert - Berechtigungen prüfen');
|
||||
}
|
||||
// Andere Fehler wurden schon in request() übersetzt
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async emailExists(localPart) {
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Plesk CLI API: Mail-Info abfragen
|
||||
const result = await this.request('POST', '/api/v2/cli/mail/call', { params: ['--info', email] });
|
||||
// Debug: Response-Struktur loggen
|
||||
console.log('Plesk emailExists response:', JSON.stringify(result, null, 2));
|
||||
// Plesk gibt code=0 bei Erfolg, code!=0 bei Fehler
|
||||
// stderr enthält Fehlermeldung wenn Mail nicht existiert
|
||||
const hasError = result.code !== 0 ||
|
||||
result.stderr?.toLowerCase().includes('not found') ||
|
||||
result.stderr?.toLowerCase().includes('does not exist') ||
|
||||
result.stderr?.toLowerCase().includes('unable to find') ||
|
||||
result.stderr?.toLowerCase().includes('no such');
|
||||
if (hasError) {
|
||||
return { exists: false };
|
||||
}
|
||||
// stdout sollte die Mail-Infos enthalten
|
||||
const exists = result.stdout?.toLowerCase().includes(localPart.toLowerCase());
|
||||
return {
|
||||
exists,
|
||||
email: exists ? email : undefined,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
// HTTP-Fehler oder Netzwerkfehler
|
||||
if (error instanceof Error) {
|
||||
const msg = error.message.toLowerCase();
|
||||
// "not found" = Mail gibt es nicht
|
||||
if (msg.includes('not found') || msg.includes('does not exist') || msg.includes('unable to find')) {
|
||||
return { exists: false };
|
||||
}
|
||||
}
|
||||
console.error('Plesk emailExists error:', error);
|
||||
return { exists: false };
|
||||
}
|
||||
}
|
||||
async createEmail(params) {
|
||||
const { localPart, forwardTargets } = params;
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob schon existiert
|
||||
const exists = await this.emailExists(localPart);
|
||||
if (exists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${email} existiert bereits`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Mail-Account mit Weiterleitung erstellen
|
||||
// Verwendet den CLI-Wrapper unter /api/v2/cli/mail/call
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: [
|
||||
'--create', email,
|
||||
'-forwarding', 'true',
|
||||
'-forwarding-addresses', forwardTargets.join(','),
|
||||
'-mailbox', 'false',
|
||||
],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `E-Mail ${email} erfolgreich erstellt mit Weiterleitung an: ${forwardTargets.join(', ')}`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk createEmail error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Erstellen der E-Mail: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
async deleteEmail(localPart) {
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob Mail existiert
|
||||
const exists = await this.emailExists(localPart);
|
||||
if (!exists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${email} nicht gefunden`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Mail-Account löschen
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: ['--remove', email],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `E-Mail ${email} erfolgreich gelöscht`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk deleteEmail error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Löschen der E-Mail: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
async renameEmail(params) {
|
||||
const { oldLocalPart, newLocalPart } = params;
|
||||
const oldEmail = `${oldLocalPart}@${this.config.domain}`;
|
||||
const newEmail = `${newLocalPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob alte Mail existiert
|
||||
const oldExists = await this.emailExists(oldLocalPart);
|
||||
if (!oldExists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${oldEmail} nicht gefunden`,
|
||||
};
|
||||
}
|
||||
// Prüfen ob neue Adresse schon existiert
|
||||
const newExists = await this.emailExists(newLocalPart);
|
||||
if (newExists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${newEmail} existiert bereits`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Mail-Account umbenennen
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: ['--rename', oldEmail, '-new-name', newLocalPart],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `E-Mail erfolgreich umbenannt von ${oldEmail} zu ${newEmail}`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk renameEmail error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Umbenennen der E-Mail: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
async updateForwardTargets(localPart, targets) {
|
||||
const email = `${localPart}@${this.config.domain}`;
|
||||
try {
|
||||
// Prüfen ob Mail existiert
|
||||
const exists = await this.emailExists(localPart);
|
||||
if (!exists.exists) {
|
||||
return {
|
||||
success: false,
|
||||
error: `E-Mail ${email} nicht gefunden`,
|
||||
};
|
||||
}
|
||||
// Plesk CLI API: Weiterleitungsziele aktualisieren
|
||||
await this.request('POST', '/api/v2/cli/mail/call', {
|
||||
params: [
|
||||
'--update', email,
|
||||
'-forwarding', 'true',
|
||||
'-forwarding-addresses', targets.join(','),
|
||||
],
|
||||
});
|
||||
return {
|
||||
success: true,
|
||||
message: `Weiterleitungen für ${email} aktualisiert: ${targets.join(', ')}`,
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unbekannter Fehler';
|
||||
console.error('Plesk updateForwardTargets error:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: `Fehler beim Aktualisieren der Weiterleitungen: ${errorMessage}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.PleskEmailProvider = PleskEmailProvider;
|
||||
//# sourceMappingURL=pleskProvider.js.map
|
||||
File diff suppressed because one or more lines are too long
+43
@@ -0,0 +1,43 @@
|
||||
export interface EmailForwardTarget {
|
||||
email: string;
|
||||
}
|
||||
export interface CreateEmailParams {
|
||||
localPart: string;
|
||||
forwardTargets: string[];
|
||||
}
|
||||
export interface RenameEmailParams {
|
||||
oldLocalPart: string;
|
||||
newLocalPart: string;
|
||||
}
|
||||
export interface EmailExistsResult {
|
||||
exists: boolean;
|
||||
email?: string;
|
||||
}
|
||||
export interface EmailOperationResult {
|
||||
success: boolean;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
export interface IEmailProvider {
|
||||
readonly type: string;
|
||||
testConnection(): Promise<void>;
|
||||
emailExists(localPart: string): Promise<EmailExistsResult>;
|
||||
createEmail(params: CreateEmailParams): Promise<EmailOperationResult>;
|
||||
deleteEmail(localPart: string): Promise<EmailOperationResult>;
|
||||
renameEmail(params: RenameEmailParams): Promise<EmailOperationResult>;
|
||||
updateForwardTargets(localPart: string, targets: string[]): Promise<EmailOperationResult>;
|
||||
}
|
||||
export interface EmailProviderConfig {
|
||||
id: number;
|
||||
name: string;
|
||||
type: 'PLESK' | 'CPANEL' | 'DIRECTADMIN';
|
||||
apiUrl: string;
|
||||
apiKey?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain: string;
|
||||
defaultForwardEmail?: string;
|
||||
isActive: boolean;
|
||||
isDefault: boolean;
|
||||
}
|
||||
//# sourceMappingURL=types.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/emailProvider/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,cAAc;IAE7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAGtB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAGhC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAG3D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAGtE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAG9D,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAGtE,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;CAC3F;AAGD,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB"}
|
||||
@@ -0,0 +1,4 @@
|
||||
"use strict";
|
||||
// ==================== EMAIL PROVIDER TYPES ====================
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=types.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/services/emailProvider/types.ts"],"names":[],"mappings":";AAAA,iEAAiE"}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
export declare function getAllPlatforms(includeInactive?: boolean): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
contactInfo: string | null;
|
||||
}[]>;
|
||||
export declare function getPlatformById(id: number): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
contactInfo: string | null;
|
||||
}) | null>;
|
||||
export declare function createPlatform(data: {
|
||||
name: string;
|
||||
contactInfo?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
contactInfo: string | null;
|
||||
}>;
|
||||
export declare function updatePlatform(id: number, data: {
|
||||
name?: string;
|
||||
contactInfo?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
contactInfo: string | null;
|
||||
}>;
|
||||
export declare function deletePlatform(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
contactInfo: string | null;
|
||||
}>;
|
||||
//# sourceMappingURL=platform.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"platform.service.d.ts","sourceRoot":"","sources":["../../src/services/platform.service.ts"],"names":[],"mappings":"AAIA,wBAAsB,eAAe,CAAC,eAAe,UAAQ;;;;;;;KAM5D;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;WAS/C;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;;;;;;;GAOA;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;GAMF;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM;;;;;;;GAa9C"}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllPlatforms = getAllPlatforms;
|
||||
exports.getPlatformById = getPlatformById;
|
||||
exports.createPlatform = createPlatform;
|
||||
exports.updatePlatform = updatePlatform;
|
||||
exports.deletePlatform = deletePlatform;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getAllPlatforms(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
return prisma.salesPlatform.findMany({
|
||||
where,
|
||||
orderBy: { name: 'asc' },
|
||||
});
|
||||
}
|
||||
async function getPlatformById(id) {
|
||||
return prisma.salesPlatform.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function createPlatform(data) {
|
||||
return prisma.salesPlatform.create({
|
||||
data: {
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updatePlatform(id, data) {
|
||||
return prisma.salesPlatform.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deletePlatform(id) {
|
||||
// Check if platform is used by any contracts
|
||||
const count = await prisma.contract.count({
|
||||
where: { salesPlatformId: id },
|
||||
});
|
||||
if (count > 0) {
|
||||
throw new Error(`Plattform kann nicht gelöscht werden, da sie von ${count} Verträgen verwendet wird`);
|
||||
}
|
||||
return prisma.salesPlatform.delete({ where: { id } });
|
||||
}
|
||||
//# sourceMappingURL=platform.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"platform.service.js","sourceRoot":"","sources":["../../src/services/platform.service.ts"],"names":[],"mappings":";;AAIA,0CAMC;AAED,0CASC;AAED,wCAUC;AAED,wCAYC;AAED,wCAaC;AA9DD,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAE3B,KAAK,UAAU,eAAe,CAAC,eAAe,GAAG,KAAK;IAC3D,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxD,OAAO,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC;QACnC,KAAK;QACL,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;KACzB,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,eAAe,CAAC,EAAU;IAC9C,OAAO,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC;QACrC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,IAGpC;IACC,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;QACjC,IAAI,EAAE;YACJ,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAClC,EAAU,EACV,IAIC;IAED,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC;QACjC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,EAAU;IAC7C,6CAA6C;IAC7C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxC,KAAK,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE;KAC/B,CAAC,CAAC;IAEH,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,oDAAoD,KAAK,2BAA2B,CACrF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AACxD,CAAC"}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
export declare function getAllProviders(includeInactive?: boolean): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
tariffs: number;
|
||||
};
|
||||
tariffs: {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
providerId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
portalUrl: string | null;
|
||||
usernameFieldName: string | null;
|
||||
passwordFieldName: string | null;
|
||||
})[]>;
|
||||
export declare function getProviderById(id: number): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
tariffs: {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
providerId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
portalUrl: string | null;
|
||||
usernameFieldName: string | null;
|
||||
passwordFieldName: string | null;
|
||||
}) | null>;
|
||||
export declare function createProvider(data: {
|
||||
name: string;
|
||||
portalUrl?: string;
|
||||
usernameFieldName?: string;
|
||||
passwordFieldName?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
portalUrl: string | null;
|
||||
usernameFieldName: string | null;
|
||||
passwordFieldName: string | null;
|
||||
}>;
|
||||
export declare function updateProvider(id: number, data: {
|
||||
name?: string;
|
||||
portalUrl?: string;
|
||||
usernameFieldName?: string;
|
||||
passwordFieldName?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
portalUrl: string | null;
|
||||
usernameFieldName: string | null;
|
||||
passwordFieldName: string | null;
|
||||
}>;
|
||||
export declare function deleteProvider(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
portalUrl: string | null;
|
||||
usernameFieldName: string | null;
|
||||
passwordFieldName: string | null;
|
||||
}>;
|
||||
//# sourceMappingURL=provider.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"provider.service.d.ts","sourceRoot":"","sources":["../../src/services/provider.service.ts"],"names":[],"mappings":"AAIA,wBAAsB,eAAe,CAAC,eAAe,UAAQ;;;;;;;;;;;;;;;;;;;;;;MAe5D;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;WAY/C;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;;;;;;;;;GAOA;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;;;GAMF;AAED,wBAAsB,cAAc,CAAC,EAAE,EAAE,MAAM;;;;;;;;;GAa9C"}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllProviders = getAllProviders;
|
||||
exports.getProviderById = getProviderById;
|
||||
exports.createProvider = createProvider;
|
||||
exports.updateProvider = updateProvider;
|
||||
exports.deleteProvider = deleteProvider;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getAllProviders(includeInactive = false) {
|
||||
const where = includeInactive ? {} : { isActive: true };
|
||||
return prisma.provider.findMany({
|
||||
where,
|
||||
orderBy: { name: 'asc' },
|
||||
include: {
|
||||
tariffs: {
|
||||
where: includeInactive ? {} : { isActive: true },
|
||||
orderBy: { name: 'asc' },
|
||||
},
|
||||
_count: {
|
||||
select: { contracts: true, tariffs: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function getProviderById(id) {
|
||||
return prisma.provider.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
tariffs: {
|
||||
orderBy: { name: 'asc' },
|
||||
},
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function createProvider(data) {
|
||||
return prisma.provider.create({
|
||||
data: {
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateProvider(id, data) {
|
||||
return prisma.provider.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteProvider(id) {
|
||||
// Check if provider is used by any contracts
|
||||
const count = await prisma.contract.count({
|
||||
where: { providerId: id },
|
||||
});
|
||||
if (count > 0) {
|
||||
throw new Error(`Anbieter kann nicht gelöscht werden, da er von ${count} Verträgen verwendet wird`);
|
||||
}
|
||||
return prisma.provider.delete({ where: { id } });
|
||||
}
|
||||
//# sourceMappingURL=provider.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"provider.service.js","sourceRoot":"","sources":["../../src/services/provider.service.ts"],"names":[],"mappings":";;AAIA,0CAeC;AAED,0CAYC;AAED,wCAYC;AAED,wCAcC;AAED,wCAaC;AA9ED,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAE3B,KAAK,UAAU,eAAe,CAAC,eAAe,GAAG,KAAK;IAC3D,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACxD,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC9B,KAAK;QACL,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;QACxB,OAAO,EAAE;YACP,OAAO,EAAE;gBACP,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAChD,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;aACzB;YACD,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;aAC3C;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,eAAe,CAAC,EAAU;IAC9C,OAAO,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;QAChC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE;YACP,OAAO,EAAE;gBACP,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;aACzB;YACD,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,IAKpC;IACC,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5B,IAAI,EAAE;YACJ,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAClC,EAAU,EACV,IAMC;IAED,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,EAAU;IAC7C,6CAA6C;IAC7C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxC,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;KAC1B,CAAC,CAAC;IAEH,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,kDAAkD,KAAK,2BAA2B,CACnF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC"}
|
||||
@@ -0,0 +1,76 @@
|
||||
export declare function getEmailsByCustomerId(customerId: number, includeInactive?: boolean): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
platform: string | null;
|
||||
isProvisioned: boolean;
|
||||
provisionedAt: Date | null;
|
||||
provisionError: string | null;
|
||||
}[]>;
|
||||
export declare function getEmailById(id: number): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
platform: string | null;
|
||||
isProvisioned: boolean;
|
||||
provisionedAt: Date | null;
|
||||
provisionError: string | null;
|
||||
} | null>;
|
||||
export declare function createEmail(data: {
|
||||
customerId: number;
|
||||
email: string;
|
||||
platform?: string;
|
||||
notes?: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
platform: string | null;
|
||||
isProvisioned: boolean;
|
||||
provisionedAt: Date | null;
|
||||
provisionError: string | null;
|
||||
}>;
|
||||
export declare function updateEmail(id: number, data: {
|
||||
email?: string;
|
||||
platform?: string;
|
||||
notes?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
platform: string | null;
|
||||
isProvisioned: boolean;
|
||||
provisionedAt: Date | null;
|
||||
provisionError: string | null;
|
||||
}>;
|
||||
export declare function deleteEmail(id: number): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
notes: string | null;
|
||||
platform: string | null;
|
||||
isProvisioned: boolean;
|
||||
provisionedAt: Date | null;
|
||||
provisionError: string | null;
|
||||
}>;
|
||||
//# sourceMappingURL=stressfreiEmail.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"stressfreiEmail.service.d.ts","sourceRoot":"","sources":["../../src/services/stressfreiEmail.service.ts"],"names":[],"mappings":"AAIA,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,UAAQ;;;;;;;;;;;;KAStF;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;UAI5C;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;;;;;;;;;;;;GAOA;AAED,wBAAsB,WAAW,CAC/B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;;;;;;GAMF;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;GAE3C"}
|
||||
@@ -0,0 +1,42 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getEmailsByCustomerId = getEmailsByCustomerId;
|
||||
exports.getEmailById = getEmailById;
|
||||
exports.createEmail = createEmail;
|
||||
exports.updateEmail = updateEmail;
|
||||
exports.deleteEmail = deleteEmail;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getEmailsByCustomerId(customerId, includeInactive = false) {
|
||||
const where = { customerId };
|
||||
if (!includeInactive) {
|
||||
where.isActive = true;
|
||||
}
|
||||
return prisma.stressfreiEmail.findMany({
|
||||
where,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
}
|
||||
async function getEmailById(id) {
|
||||
return prisma.stressfreiEmail.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
}
|
||||
async function createEmail(data) {
|
||||
return prisma.stressfreiEmail.create({
|
||||
data: {
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateEmail(id, data) {
|
||||
return prisma.stressfreiEmail.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteEmail(id) {
|
||||
return prisma.stressfreiEmail.delete({ where: { id } });
|
||||
}
|
||||
//# sourceMappingURL=stressfreiEmail.service.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"stressfreiEmail.service.js","sourceRoot":"","sources":["../../src/services/stressfreiEmail.service.ts"],"names":[],"mappings":";;AAIA,sDASC;AAED,oCAIC;AAED,kCAYC;AAED,kCAaC;AAED,kCAEC;AApDD,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAE3B,KAAK,UAAU,qBAAqB,CAAC,UAAkB,EAAE,eAAe,GAAG,KAAK;IACrF,MAAM,KAAK,GAA4B,EAAE,UAAU,EAAE,CAAC;IACtD,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,MAAM,CAAC,eAAe,CAAC,QAAQ,CAAC;QACrC,KAAK;QACL,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;KAC/B,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,OAAO,MAAM,CAAC,eAAe,CAAC,UAAU,CAAC;QACvC,KAAK,EAAE,EAAE,EAAE,EAAE;KACd,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,WAAW,CAAC,IAKjC;IACC,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC;QACnC,IAAI,EAAE;YACJ,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,WAAW,CAC/B,EAAU,EACV,IAKC;IAED,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC;QACnC,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,WAAW,CAAC,EAAU;IAC1C,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC1D,CAAC"}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
export declare function getTariffsByProvider(providerId: number, includeInactive?: boolean): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
providerId: number;
|
||||
})[]>;
|
||||
export declare function getTariffById(id: number): Promise<({
|
||||
_count: {
|
||||
contracts: number;
|
||||
};
|
||||
provider: {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
portalUrl: string | null;
|
||||
usernameFieldName: string | null;
|
||||
passwordFieldName: string | null;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
providerId: number;
|
||||
}) | null>;
|
||||
export declare function createTariff(data: {
|
||||
providerId: number;
|
||||
name: string;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
providerId: number;
|
||||
}>;
|
||||
export declare function updateTariff(id: number, data: {
|
||||
name?: string;
|
||||
isActive?: boolean;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
providerId: number;
|
||||
}>;
|
||||
export declare function deleteTariff(id: number): Promise<{
|
||||
id: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
providerId: number;
|
||||
}>;
|
||||
//# sourceMappingURL=tariff.service.d.ts.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"tariff.service.d.ts","sourceRoot":"","sources":["../../src/services/tariff.service.ts"],"names":[],"mappings":"AAIA,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,UAAQ;;;;;;;;;;;MAcrF;AAED,wBAAsB,aAAa,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;WAU7C;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;;;;;;;GAOA;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;;;;;;;GAMF;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM;;;;;;;GAa5C"}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getTariffsByProvider = getTariffsByProvider;
|
||||
exports.getTariffById = getTariffById;
|
||||
exports.createTariff = createTariff;
|
||||
exports.updateTariff = updateTariff;
|
||||
exports.deleteTariff = deleteTariff;
|
||||
const client_1 = require("@prisma/client");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getTariffsByProvider(providerId, includeInactive = false) {
|
||||
const where = { providerId };
|
||||
if (!includeInactive) {
|
||||
where.isActive = true;
|
||||
}
|
||||
return prisma.tariff.findMany({
|
||||
where,
|
||||
orderBy: { name: 'asc' },
|
||||
include: {
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function getTariffById(id) {
|
||||
return prisma.tariff.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
provider: true,
|
||||
_count: {
|
||||
select: { contracts: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function createTariff(data) {
|
||||
return prisma.tariff.create({
|
||||
data: {
|
||||
...data,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateTariff(id, data) {
|
||||
return prisma.tariff.update({
|
||||
where: { id },
|
||||
data,
|
||||
});
|
||||
}
|
||||
async function deleteTariff(id) {
|
||||
// Check if tariff is used by any contracts
|
||||
const count = await prisma.contract.count({
|
||||
where: { tariffId: id },
|
||||
});
|
||||
if (count > 0) {
|
||||
throw new Error(`Tarif kann nicht gelöscht werden, da er von ${count} Verträgen verwendet wird`);
|
||||
}
|
||||
return prisma.tariff.delete({ where: { id } });
|
||||
}
|
||||
//# sourceMappingURL=tariff.service.js.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"tariff.service.js","sourceRoot":"","sources":["../../src/services/tariff.service.ts"],"names":[],"mappings":";;AAIA,oDAcC;AAED,sCAUC;AAED,oCAUC;AAED,oCAWC;AAED,oCAaC;AAtED,2CAA8C;AAE9C,MAAM,MAAM,GAAG,IAAI,qBAAY,EAAE,CAAC;AAE3B,KAAK,UAAU,oBAAoB,CAAC,UAAkB,EAAE,eAAe,GAAG,KAAK;IACpF,MAAM,KAAK,GAA+C,EAAE,UAAU,EAAE,CAAC;IACzE,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;QAC5B,KAAK;QACL,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;QACxB,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,EAAU;IAC5C,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;QAC9B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,OAAO,EAAE;YACP,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE;aAC5B;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,IAGlC;IACC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1B,IAAI,EAAE;YACJ,GAAG,IAAI;YACP,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,EAAU,EACV,IAGC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,EAAE,EAAE,EAAE;QACb,IAAI;KACL,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,2CAA2C;IAC3C,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QACxC,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;KACxB,CAAC,CAAC;IAEH,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,+CAA+C,KAAK,2BAA2B,CAChF,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AACjD,CAAC"}
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
export interface UserFilters {
|
||||
search?: string;
|
||||
isActive?: boolean;
|
||||
roleId?: number;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
}
|
||||
export declare function getAllUsers(filters: UserFilters): Promise<{
|
||||
users: {
|
||||
roles: ({
|
||||
permissions: {
|
||||
roleId: number;
|
||||
permissionId: number;
|
||||
}[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
})[];
|
||||
hasDeveloperAccess: boolean;
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
}[];
|
||||
pagination: {
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
totalPages: number;
|
||||
};
|
||||
}>;
|
||||
export declare function getUserById(id: number): Promise<{
|
||||
roles: ({
|
||||
permissions: ({
|
||||
permission: {
|
||||
id: number;
|
||||
resource: string;
|
||||
action: string;
|
||||
};
|
||||
} & {
|
||||
roleId: number;
|
||||
permissionId: number;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
})[];
|
||||
permissions: string[];
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
} | null>;
|
||||
export declare function createUser(data: {
|
||||
email: string;
|
||||
password: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
roleIds: number[];
|
||||
customerId?: number;
|
||||
}): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
isActive: boolean;
|
||||
roles: ({
|
||||
role: {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
};
|
||||
} & {
|
||||
userId: number;
|
||||
roleId: number;
|
||||
})[];
|
||||
}>;
|
||||
export declare function updateUser(id: number, data: {
|
||||
email?: string;
|
||||
password?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
isActive?: boolean;
|
||||
roleIds?: number[];
|
||||
customerId?: number;
|
||||
hasDeveloperAccess?: boolean;
|
||||
}): Promise<{
|
||||
roles: ({
|
||||
permissions: ({
|
||||
permission: {
|
||||
id: number;
|
||||
resource: string;
|
||||
action: string;
|
||||
};
|
||||
} & {
|
||||
roleId: number;
|
||||
permissionId: number;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
})[];
|
||||
permissions: string[];
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number | null;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
} | null>;
|
||||
export declare function deleteUser(id: number): Promise<{
|
||||
id: number;
|
||||
email: string;
|
||||
customerId: number | null;
|
||||
password: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}>;
|
||||
export declare function getAllRoles(): Promise<({
|
||||
permissions: ({
|
||||
permission: {
|
||||
id: number;
|
||||
resource: string;
|
||||
action: string;
|
||||
};
|
||||
} & {
|
||||
roleId: number;
|
||||
permissionId: number;
|
||||
})[];
|
||||
_count: {
|
||||
users: number;
|
||||
};
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
})[]>;
|
||||
export declare function getRoleById(id: number): Promise<({
|
||||
permissions: ({
|
||||
permission: {
|
||||
id: number;
|
||||
resource: string;
|
||||
action: string;
|
||||
};
|
||||
} & {
|
||||
roleId: number;
|
||||
permissionId: number;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
}) | null>;
|
||||
export declare function createRole(data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
permissionIds: number[];
|
||||
}): Promise<{
|
||||
permissions: ({
|
||||
permission: {
|
||||
id: number;
|
||||
resource: string;
|
||||
action: string;
|
||||
};
|
||||
} & {
|
||||
roleId: number;
|
||||
permissionId: number;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
}>;
|
||||
export declare function updateRole(id: number, data: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
permissionIds?: number[];
|
||||
}): Promise<({
|
||||
permissions: ({
|
||||
permission: {
|
||||
id: number;
|
||||
resource: string;
|
||||
action: string;
|
||||
};
|
||||
} & {
|
||||
roleId: number;
|
||||
permissionId: number;
|
||||
})[];
|
||||
} & {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
}) | null>;
|
||||
export declare function deleteRole(id: number): Promise<{
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
name: string;
|
||||
description: string | null;
|
||||
}>;
|
||||
export declare function getAllPermissions(): Promise<{
|
||||
id: number;
|
||||
resource: string;
|
||||
action: string;
|
||||
}[]>;
|
||||
//# sourceMappingURL=user.service.d.ts.map
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"user.service.d.ts","sourceRoot":"","sources":["../../src/services/user.service.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqErD;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA0C3C;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;;;;;;;;;;;;;;;;;;;GA0BA;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAsHF;AA0DD,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;GA6D1C;AAGD,wBAAsB,WAAW;;;;;;;;;;;;;;;;;;;;MAYhC;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;WAS3C;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;;;;;;;;;;;;;;;;;GAeA;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;;;;;;;;;;;;;;;;;WAiBF;AAED,wBAAsB,UAAU,CAAC,EAAE,EAAE,MAAM;;;;;;GAU1C;AAGD,wBAAsB,iBAAiB;;;;KAItC"}
|
||||
+415
@@ -0,0 +1,415 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getAllUsers = getAllUsers;
|
||||
exports.getUserById = getUserById;
|
||||
exports.createUser = createUser;
|
||||
exports.updateUser = updateUser;
|
||||
exports.deleteUser = deleteUser;
|
||||
exports.getAllRoles = getAllRoles;
|
||||
exports.getRoleById = getRoleById;
|
||||
exports.createRole = createRole;
|
||||
exports.updateRole = updateRole;
|
||||
exports.deleteRole = deleteRole;
|
||||
exports.getAllPermissions = getAllPermissions;
|
||||
const client_1 = require("@prisma/client");
|
||||
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
||||
const helpers_js_1 = require("../utils/helpers.js");
|
||||
const prisma = new client_1.PrismaClient();
|
||||
async function getAllUsers(filters) {
|
||||
const { search, isActive, roleId, page = 1, limit = 20 } = filters;
|
||||
const { skip, take } = (0, helpers_js_1.paginate)(page, limit);
|
||||
const where = {};
|
||||
if (isActive !== undefined) {
|
||||
where.isActive = isActive;
|
||||
}
|
||||
if (roleId) {
|
||||
where.roles = { some: { roleId } };
|
||||
}
|
||||
if (search) {
|
||||
where.OR = [
|
||||
{ email: { contains: search } },
|
||||
{ firstName: { contains: search } },
|
||||
{ lastName: { contains: search } },
|
||||
];
|
||||
}
|
||||
const [users, total] = await Promise.all([
|
||||
prisma.user.findMany({
|
||||
where,
|
||||
skip,
|
||||
take,
|
||||
orderBy: { createdAt: 'desc' },
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
isActive: true,
|
||||
customerId: true,
|
||||
createdAt: true,
|
||||
roles: {
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.user.count({ where }),
|
||||
]);
|
||||
// Get Developer role ID
|
||||
const developerRole = await prisma.role.findFirst({
|
||||
where: { name: 'Developer' },
|
||||
});
|
||||
return {
|
||||
users: users.map((u) => {
|
||||
// Check if user has developer role assigned
|
||||
const hasDeveloperAccess = developerRole
|
||||
? u.roles.some((ur) => ur.roleId === developerRole.id)
|
||||
: false;
|
||||
return {
|
||||
...u,
|
||||
roles: u.roles.map((r) => r.role),
|
||||
hasDeveloperAccess,
|
||||
};
|
||||
}),
|
||||
pagination: (0, helpers_js_1.buildPaginationResponse)(page, limit, total),
|
||||
};
|
||||
}
|
||||
async function getUserById(id) {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
isActive: true,
|
||||
customerId: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
roles: {
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!user)
|
||||
return null;
|
||||
const permissions = new Set();
|
||||
for (const userRole of user.roles) {
|
||||
for (const rolePerm of userRole.role.permissions) {
|
||||
permissions.add(`${rolePerm.permission.resource}:${rolePerm.permission.action}`);
|
||||
}
|
||||
}
|
||||
return {
|
||||
...user,
|
||||
roles: user.roles.map((r) => r.role),
|
||||
permissions: Array.from(permissions),
|
||||
};
|
||||
}
|
||||
async function createUser(data) {
|
||||
const hashedPassword = await bcryptjs_1.default.hash(data.password, 10);
|
||||
return prisma.user.create({
|
||||
data: {
|
||||
email: data.email,
|
||||
password: hashedPassword,
|
||||
firstName: data.firstName,
|
||||
lastName: data.lastName,
|
||||
customerId: data.customerId,
|
||||
roles: {
|
||||
create: data.roleIds.map((roleId) => ({ roleId })),
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
email: true,
|
||||
firstName: true,
|
||||
lastName: true,
|
||||
isActive: true,
|
||||
customerId: true,
|
||||
roles: {
|
||||
include: { role: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateUser(id, data) {
|
||||
const { roleIds, password, hasDeveloperAccess, ...userData } = data;
|
||||
// Check if this would remove the last admin
|
||||
const isBeingDeactivated = userData.isActive === false;
|
||||
const rolesAreBeingChanged = roleIds !== undefined;
|
||||
if (isBeingDeactivated || rolesAreBeingChanged) {
|
||||
// Check if user currently has admin permissions
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
roles: {
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const isCurrentlyAdmin = currentUser?.roles.some((ur) => ur.role.permissions.some((rp) => rp.permission.resource === 'users' && rp.permission.action === 'delete'));
|
||||
if (isCurrentlyAdmin) {
|
||||
// Check if user will still be admin after role change
|
||||
let willStillBeAdmin = false;
|
||||
if (rolesAreBeingChanged) {
|
||||
const newRoles = await prisma.role.findMany({
|
||||
where: { id: { in: roleIds } },
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
willStillBeAdmin = newRoles.some((role) => role.permissions.some((rp) => rp.permission.resource === 'users' && rp.permission.action === 'delete'));
|
||||
}
|
||||
else {
|
||||
willStillBeAdmin = true; // Roles not being changed
|
||||
}
|
||||
// If user is losing admin status or being deactivated, check for other admins
|
||||
if (!willStillBeAdmin || isBeingDeactivated) {
|
||||
const otherAdminCount = await prisma.user.count({
|
||||
where: {
|
||||
id: { not: id },
|
||||
isActive: true,
|
||||
roles: {
|
||||
some: {
|
||||
role: {
|
||||
permissions: {
|
||||
some: {
|
||||
permission: {
|
||||
resource: 'users',
|
||||
action: 'delete',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (otherAdminCount === 0) {
|
||||
if (isBeingDeactivated) {
|
||||
throw new Error('Dieser Benutzer ist der letzte Administrator und kann nicht deaktiviert werden');
|
||||
}
|
||||
else {
|
||||
throw new Error('Die Admin-Rolle kann nicht entfernt werden, da dies der letzte Administrator ist');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Hash password if provided
|
||||
if (password) {
|
||||
userData.password = await bcryptjs_1.default.hash(password, 10);
|
||||
}
|
||||
// Update user
|
||||
await prisma.user.update({
|
||||
where: { id },
|
||||
data: userData,
|
||||
});
|
||||
// Update roles if provided
|
||||
if (roleIds) {
|
||||
await prisma.userRole.deleteMany({ where: { userId: id } });
|
||||
await prisma.userRole.createMany({
|
||||
data: roleIds.map((roleId) => ({ userId: id, roleId })),
|
||||
});
|
||||
}
|
||||
// Handle developer access
|
||||
console.log('updateUser - hasDeveloperAccess:', hasDeveloperAccess);
|
||||
if (hasDeveloperAccess !== undefined) {
|
||||
await setUserDeveloperAccess(id, hasDeveloperAccess);
|
||||
}
|
||||
return getUserById(id);
|
||||
}
|
||||
// Helper to set developer access for a user
|
||||
async function setUserDeveloperAccess(userId, enabled) {
|
||||
console.log('setUserDeveloperAccess called - userId:', userId, 'enabled:', enabled);
|
||||
// Get or create developer:access permission
|
||||
let developerPerm = await prisma.permission.findFirst({
|
||||
where: { resource: 'developer', action: 'access' },
|
||||
});
|
||||
if (!developerPerm) {
|
||||
developerPerm = await prisma.permission.create({
|
||||
data: { resource: 'developer', action: 'access' },
|
||||
});
|
||||
}
|
||||
// Get or create Developer role
|
||||
let developerRole = await prisma.role.findFirst({
|
||||
where: { name: 'Developer' },
|
||||
});
|
||||
if (!developerRole) {
|
||||
developerRole = await prisma.role.create({
|
||||
data: {
|
||||
name: 'Developer',
|
||||
description: 'Entwicklerzugriff auf Datenbanktools',
|
||||
permissions: {
|
||||
create: [{ permissionId: developerPerm.id }],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
// Check if user already has Developer role
|
||||
const hasRole = await prisma.userRole.findFirst({
|
||||
where: { userId, roleId: developerRole.id },
|
||||
});
|
||||
console.log('setUserDeveloperAccess - developerRole.id:', developerRole.id, 'hasRole:', hasRole);
|
||||
if (enabled && !hasRole) {
|
||||
// Add Developer role
|
||||
console.log('Adding Developer role');
|
||||
await prisma.userRole.create({
|
||||
data: { userId, roleId: developerRole.id },
|
||||
});
|
||||
}
|
||||
else if (!enabled && hasRole) {
|
||||
// Remove Developer role
|
||||
console.log('Removing Developer role');
|
||||
await prisma.userRole.delete({
|
||||
where: { userId_roleId: { userId, roleId: developerRole.id } },
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.log('No action needed - enabled:', enabled, 'hasRole:', !!hasRole);
|
||||
}
|
||||
}
|
||||
async function deleteUser(id) {
|
||||
// Check if user is an admin
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
roles: {
|
||||
include: {
|
||||
role: {
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!user) {
|
||||
throw new Error('Benutzer nicht gefunden');
|
||||
}
|
||||
// Check if user has admin permissions (users:delete means admin)
|
||||
const isAdmin = user.roles.some((ur) => ur.role.permissions.some((rp) => rp.permission.resource === 'users' && rp.permission.action === 'delete'));
|
||||
if (isAdmin) {
|
||||
// Count other admins (users with users:delete permission)
|
||||
const adminCount = await prisma.user.count({
|
||||
where: {
|
||||
id: { not: id },
|
||||
isActive: true,
|
||||
roles: {
|
||||
some: {
|
||||
role: {
|
||||
permissions: {
|
||||
some: {
|
||||
permission: {
|
||||
resource: 'users',
|
||||
action: 'delete',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (adminCount === 0) {
|
||||
throw new Error('Dieser Benutzer ist der letzte Administrator und kann nicht gelöscht werden');
|
||||
}
|
||||
}
|
||||
return prisma.user.delete({ where: { id } });
|
||||
}
|
||||
// Role operations
|
||||
async function getAllRoles() {
|
||||
return prisma.role.findMany({
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
_count: {
|
||||
select: { users: true },
|
||||
},
|
||||
},
|
||||
orderBy: { name: 'asc' },
|
||||
});
|
||||
}
|
||||
async function getRoleById(id) {
|
||||
return prisma.role.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function createRole(data) {
|
||||
return prisma.role.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
permissions: {
|
||||
create: data.permissionIds.map((permissionId) => ({ permissionId })),
|
||||
},
|
||||
},
|
||||
include: {
|
||||
permissions: {
|
||||
include: { permission: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
async function updateRole(id, data) {
|
||||
const { permissionIds, ...roleData } = data;
|
||||
await prisma.role.update({
|
||||
where: { id },
|
||||
data: roleData,
|
||||
});
|
||||
if (permissionIds) {
|
||||
await prisma.rolePermission.deleteMany({ where: { roleId: id } });
|
||||
await prisma.rolePermission.createMany({
|
||||
data: permissionIds.map((permissionId) => ({ roleId: id, permissionId })),
|
||||
});
|
||||
}
|
||||
return getRoleById(id);
|
||||
}
|
||||
async function deleteRole(id) {
|
||||
// Check if role is assigned to any users
|
||||
const count = await prisma.userRole.count({ where: { roleId: id } });
|
||||
if (count > 0) {
|
||||
throw new Error(`Rolle kann nicht gelöscht werden, da sie ${count} Benutzern zugewiesen ist`);
|
||||
}
|
||||
return prisma.role.delete({ where: { id } });
|
||||
}
|
||||
// Permission operations
|
||||
async function getAllPermissions() {
|
||||
return prisma.permission.findMany({
|
||||
orderBy: [{ resource: 'asc' }, { action: 'asc' }],
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=user.service.js.map
|
||||
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user