From 57e6a2ea45cf36dceb3880b75bf43664592ca60f Mon Sep 17 00:00:00 2001 From: richardtekula Date: Wed, 28 Jan 2026 07:43:32 +0100 Subject: [PATCH] refactor: Split ai-kurzy.service.js into domain-specific files Split 445-line monolith into: - ai-kurzy/kurzy.service.js: course CRUD + stats - ai-kurzy/ucastnici.service.js: participant CRUD - ai-kurzy/registracie.service.js: registration CRUD, combined table, field updates, and document (prilohy) operations Original ai-kurzy.service.js becomes a barrel export preserving all existing import paths. Co-Authored-By: Claude Opus 4.5 --- src/services/ai-kurzy.service.js | 452 +------------------ src/services/ai-kurzy/kurzy.service.js | 105 +++++ src/services/ai-kurzy/registracie.service.js | 234 ++++++++++ src/services/ai-kurzy/ucastnici.service.js | 88 ++++ 4 files changed, 434 insertions(+), 445 deletions(-) create mode 100644 src/services/ai-kurzy/kurzy.service.js create mode 100644 src/services/ai-kurzy/registracie.service.js create mode 100644 src/services/ai-kurzy/ucastnici.service.js diff --git a/src/services/ai-kurzy.service.js b/src/services/ai-kurzy.service.js index 0f95f4b..cf14a0c 100644 --- a/src/services/ai-kurzy.service.js +++ b/src/services/ai-kurzy.service.js @@ -1,445 +1,7 @@ -import { db } from '../config/database.js'; -import { kurzy, ucastnici, registracie, prilohy } from '../db/schema.js'; -import { and, desc, eq, sql, asc } from 'drizzle-orm'; -import { NotFoundError } from '../utils/errors.js'; - -// ==================== KURZY (Courses) ==================== - -export const getAllKurzy = async () => { - const result = await db - .select({ - id: kurzy.id, - nazov: kurzy.nazov, - typKurzu: kurzy.typKurzu, - popis: kurzy.popis, - cena: kurzy.cena, - maxKapacita: kurzy.maxKapacita, - aktivny: kurzy.aktivny, - farba: kurzy.farba, - createdAt: kurzy.createdAt, - registraciiCount: sql`(SELECT COUNT(*) FROM registracie WHERE kurz_id = ${kurzy.id})::int`, - }) - .from(kurzy) - .orderBy(asc(kurzy.nazov)); - - return result; -}; - -export const getKurzById = async (id) => { - const [kurz] = await db - .select() - .from(kurzy) - .where(eq(kurzy.id, id)) - .limit(1); - - if (!kurz) { - throw new NotFoundError('Kurz nenájdený'); - } - - return kurz; -}; - -export const createKurz = async (data) => { - const [newKurz] = await db - .insert(kurzy) - .values({ - nazov: data.nazov, - typKurzu: data.typKurzu, - popis: data.popis || null, - cena: data.cena, - maxKapacita: data.maxKapacita || null, - aktivny: data.aktivny !== undefined ? data.aktivny : true, - farba: data.farba || null, - }) - .returning(); - - return newKurz; -}; - -export const updateKurz = async (id, data) => { - await getKurzById(id); - - const updateData = { - nazov: data.nazov, - typKurzu: data.typKurzu, - popis: data.popis !== undefined ? data.popis : undefined, - cena: data.cena, - maxKapacita: data.maxKapacita !== undefined ? data.maxKapacita : undefined, - aktivny: data.aktivny !== undefined ? data.aktivny : undefined, - farba: data.farba !== undefined ? data.farba : undefined, - updatedAt: new Date(), - }; - - // Remove undefined values - Object.keys(updateData).forEach(key => { - if (updateData[key] === undefined) { - delete updateData[key]; - } - }); - - const [updated] = await db - .update(kurzy) - .set(updateData) - .where(eq(kurzy.id, id)) - .returning(); - - return updated; -}; - -export const deleteKurz = async (id) => { - await getKurzById(id); - await db.delete(kurzy).where(eq(kurzy.id, id)); - return { success: true, message: 'Kurz bol odstránený' }; -}; - -// ==================== UCASTNICI (Participants) ==================== - -export const getAllUcastnici = async () => { - const result = await db - .select({ - id: ucastnici.id, - titul: ucastnici.titul, - meno: ucastnici.meno, - priezvisko: ucastnici.priezvisko, - email: ucastnici.email, - telefon: ucastnici.telefon, - firma: ucastnici.firma, - firmaIco: ucastnici.firmaIco, - firmaDic: ucastnici.firmaDic, - firmaIcDph: ucastnici.firmaIcDph, - firmaSidlo: ucastnici.firmaSidlo, - mesto: ucastnici.mesto, - ulica: ucastnici.ulica, - psc: ucastnici.psc, - createdAt: ucastnici.createdAt, - registraciiCount: sql`(SELECT COUNT(*) FROM registracie WHERE ucastnik_id = ${ucastnici.id})::int`, - }) - .from(ucastnici) - .orderBy(asc(ucastnici.priezvisko), asc(ucastnici.meno)); - - return result; -}; - -export const getUcastnikById = async (id) => { - const [ucastnik] = await db - .select() - .from(ucastnici) - .where(eq(ucastnici.id, id)) - .limit(1); - - if (!ucastnik) { - throw new NotFoundError('Účastník nenájdený'); - } - - return ucastnik; -}; - -export const createUcastnik = async (data) => { - const [newUcastnik] = await db - .insert(ucastnici) - .values({ - titul: data.titul || null, - meno: data.meno, - priezvisko: data.priezvisko, - email: data.email, - telefon: data.telefon || null, - firma: data.firma || null, - firmaIco: data.firmaIco || null, - firmaDic: data.firmaDic || null, - firmaIcDph: data.firmaIcDph || null, - firmaSidlo: data.firmaSidlo || null, - mesto: data.mesto || null, - ulica: data.ulica || null, - psc: data.psc || null, - }) - .returning(); - - return newUcastnik; -}; - -export const updateUcastnik = async (id, data) => { - await getUcastnikById(id); - - const [updated] = await db - .update(ucastnici) - .set({ - ...data, - updatedAt: new Date(), - }) - .where(eq(ucastnici.id, id)) - .returning(); - - return updated; -}; - -export const deleteUcastnik = async (id) => { - await getUcastnikById(id); - await db.delete(ucastnici).where(eq(ucastnici.id, id)); - return { success: true, message: 'Účastník bol odstránený' }; -}; - -// ==================== REGISTRACIE (Registrations) ==================== - -export const getAllRegistracie = async (kurzId = null) => { - const conditions = kurzId ? [eq(registracie.kurzId, kurzId)] : []; - - const result = await db - .select({ - id: registracie.id, - kurzId: registracie.kurzId, - ucastnikId: registracie.ucastnikId, - datumOd: registracie.datumOd, - datumDo: registracie.datumDo, - formaKurzu: registracie.formaKurzu, - pocetUcastnikov: registracie.pocetUcastnikov, - fakturaCislo: registracie.fakturaCislo, - fakturaVystavena: registracie.fakturaVystavena, - zaplatene: registracie.zaplatene, - stav: registracie.stav, - poznamka: registracie.poznamka, - createdAt: registracie.createdAt, - // Kurz info - kurzNazov: kurzy.nazov, - kurzTyp: kurzy.typKurzu, - // Ucastnik info - ucastnikMeno: ucastnici.meno, - ucastnikPriezvisko: ucastnici.priezvisko, - ucastnikEmail: ucastnici.email, - ucastnikFirma: ucastnici.firma, - }) - .from(registracie) - .leftJoin(kurzy, eq(registracie.kurzId, kurzy.id)) - .leftJoin(ucastnici, eq(registracie.ucastnikId, ucastnici.id)) - .where(conditions.length > 0 ? and(...conditions) : undefined) - .orderBy(desc(registracie.datumOd), desc(registracie.createdAt)); - - return result; -}; - -export const getRegistraciaById = async (id) => { - const [reg] = await db - .select({ - id: registracie.id, - kurzId: registracie.kurzId, - ucastnikId: registracie.ucastnikId, - formaKurzu: registracie.formaKurzu, - pocetUcastnikov: registracie.pocetUcastnikov, - fakturaCislo: registracie.fakturaCislo, - fakturaVystavena: registracie.fakturaVystavena, - zaplatene: registracie.zaplatene, - stav: registracie.stav, - poznamka: registracie.poznamka, - createdAt: registracie.createdAt, - kurzNazov: kurzy.nazov, - kurzTyp: kurzy.typKurzu, - ucastnikMeno: ucastnici.meno, - ucastnikPriezvisko: ucastnici.priezvisko, - ucastnikEmail: ucastnici.email, - }) - .from(registracie) - .leftJoin(kurzy, eq(registracie.kurzId, kurzy.id)) - .leftJoin(ucastnici, eq(registracie.ucastnikId, ucastnici.id)) - .where(eq(registracie.id, id)) - .limit(1); - - if (!reg) { - throw new NotFoundError('Registrácia nenájdená'); - } - - return reg; -}; - -export const createRegistracia = async (data) => { - const [newReg] = await db - .insert(registracie) - .values({ - kurzId: data.kurzId, - ucastnikId: data.ucastnikId, - datumOd: data.datumOd ? new Date(data.datumOd) : null, - datumDo: data.datumDo ? new Date(data.datumDo) : null, - formaKurzu: data.formaKurzu || 'prezencne', - pocetUcastnikov: data.pocetUcastnikov || 1, - fakturaCislo: data.fakturaCislo || null, - fakturaVystavena: data.fakturaVystavena || false, - zaplatene: data.zaplatene || false, - stav: data.stav || 'registrovany', - poznamka: data.poznamka || null, - }) - .returning(); - - return newReg; -}; - -export const updateRegistracia = async (id, data) => { - await getRegistraciaById(id); - - const [updated] = await db - .update(registracie) - .set({ - ...data, - updatedAt: new Date(), - }) - .where(eq(registracie.id, id)) - .returning(); - - return updated; -}; - -export const deleteRegistracia = async (id) => { - await getRegistraciaById(id); - await db.delete(registracie).where(eq(registracie.id, id)); - return { success: true, message: 'Registrácia bola odstránená' }; -}; - -// ==================== COMBINED TABLE VIEW (Excel-style) ==================== - -export const getCombinedTableData = async () => { - const result = await db - .select({ - // Registration ID (main row identifier) - id: registracie.id, - // Ucastnik fields - ucastnikId: ucastnici.id, - titul: ucastnici.titul, - meno: ucastnici.meno, - priezvisko: ucastnici.priezvisko, - email: ucastnici.email, - telefon: ucastnici.telefon, - firma: ucastnici.firma, - firmaIco: ucastnici.firmaIco, - firmaDic: ucastnici.firmaDic, - firmaIcDph: ucastnici.firmaIcDph, - firmaSidlo: ucastnici.firmaSidlo, - mesto: ucastnici.mesto, - ulica: ucastnici.ulica, - psc: ucastnici.psc, - // Kurz fields - kurzId: kurzy.id, - kurzNazov: kurzy.nazov, - kurzTyp: kurzy.typKurzu, - kurzFarba: kurzy.farba, - // Registration fields (dates are now here) - datumOd: registracie.datumOd, - datumDo: registracie.datumDo, - formaKurzu: registracie.formaKurzu, - pocetUcastnikov: registracie.pocetUcastnikov, - fakturaCislo: registracie.fakturaCislo, - fakturaVystavena: registracie.fakturaVystavena, - zaplatene: registracie.zaplatene, - stav: registracie.stav, - poznamka: registracie.poznamka, - createdAt: registracie.createdAt, - // Document count - dokumentyCount: sql`(SELECT COUNT(*) FROM prilohy WHERE registracia_id = ${registracie.id})::int`, - }) - .from(registracie) - .innerJoin(ucastnici, eq(registracie.ucastnikId, ucastnici.id)) - .innerJoin(kurzy, eq(registracie.kurzId, kurzy.id)) - .orderBy(desc(registracie.datumOd), desc(registracie.createdAt)); - - return result; -}; - -// Update a single field (for inline editing) -export const updateField = async (registrationId, field, value) => { - // Determine which table to update based on the field - const ucastnikFields = ['titul', 'meno', 'priezvisko', 'email', 'telefon', 'firma', 'firmaIco', 'firmaDic', 'firmaIcDph', 'firmaSidlo', 'mesto', 'ulica', 'psc']; - const registraciaFields = ['datumOd', 'datumDo', 'formaKurzu', 'pocetUcastnikov', 'fakturaCislo', 'fakturaVystavena', 'zaplatene', 'stav', 'poznamka', 'kurzId']; - const dateFields = ['datumOd', 'datumDo']; - - // Get the registration to find ucastnikId - const [reg] = await db - .select({ ucastnikId: registracie.ucastnikId }) - .from(registracie) - .where(eq(registracie.id, registrationId)) - .limit(1); - - if (!reg) { - throw new NotFoundError('Registrácia nenájdená'); - } - - // Convert date strings to Date objects - let processedValue = value; - if (dateFields.includes(field)) { - processedValue = value ? new Date(value) : null; - } - - if (ucastnikFields.includes(field)) { - // Update ucastnik table - await db - .update(ucastnici) - .set({ [field]: processedValue, updatedAt: new Date() }) - .where(eq(ucastnici.id, reg.ucastnikId)); - } else if (registraciaFields.includes(field)) { - // Update registracie table - await db - .update(registracie) - .set({ [field]: processedValue, updatedAt: new Date() }) - .where(eq(registracie.id, registrationId)); - } else { - throw new Error(`Unknown field: ${field}`); - } - - return { success: true }; -}; - -// ==================== PRILOHY (Documents) ==================== - -export const getPrilohyByRegistracia = async (registraciaId) => { - const result = await db - .select() - .from(prilohy) - .where(eq(prilohy.registraciaId, registraciaId)) - .orderBy(desc(prilohy.createdAt)); - - return result; -}; - -export const createPriloha = async (data) => { - const [newPriloha] = await db - .insert(prilohy) - .values({ - registraciaId: data.registraciaId, - nazovSuboru: data.nazovSuboru, - typPrilohy: data.typPrilohy || 'ine', - cestaKSuboru: data.cestaKSuboru, - mimeType: data.mimeType || null, - velkostSuboru: data.velkostSuboru || null, - popis: data.popis || null, - }) - .returning(); - - return newPriloha; -}; - -export const deletePriloha = async (id) => { - const [priloha] = await db - .select() - .from(prilohy) - .where(eq(prilohy.id, id)) - .limit(1); - - if (!priloha) { - throw new NotFoundError('Príloha nenájdená'); - } - - await db.delete(prilohy).where(eq(prilohy.id, id)); - return { success: true, filePath: priloha.cestaKSuboru }; -}; - -// ==================== STATISTICS ==================== - -export const getKurzyStats = async () => { - const [stats] = await db - .select({ - totalKurzy: sql`(SELECT COUNT(*) FROM kurzy)::int`, - aktivneKurzy: sql`(SELECT COUNT(*) FROM kurzy WHERE aktivny = true)::int`, - totalUcastnici: sql`(SELECT COUNT(*) FROM ucastnici)::int`, - totalRegistracie: sql`(SELECT COUNT(*) FROM registracie)::int`, - zaplateneRegistracie: sql`(SELECT COUNT(*) FROM registracie WHERE zaplatene = true)::int`, - absolvovaneRegistracie: sql`(SELECT COUNT(*) FROM registracie WHERE stav = 'absolvoval')::int`, - }) - .from(sql`(SELECT 1) AS dummy`); - - return stats; -}; +export { getAllKurzy, getKurzById, createKurz, updateKurz, deleteKurz, getKurzyStats } from './ai-kurzy/kurzy.service.js'; +export { getAllUcastnici, getUcastnikById, createUcastnik, updateUcastnik, deleteUcastnik } from './ai-kurzy/ucastnici.service.js'; +export { + getAllRegistracie, getRegistraciaById, createRegistracia, updateRegistracia, deleteRegistracia, + getCombinedTableData, updateField, + getPrilohyByRegistracia, createPriloha, deletePriloha, +} from './ai-kurzy/registracie.service.js'; diff --git a/src/services/ai-kurzy/kurzy.service.js b/src/services/ai-kurzy/kurzy.service.js new file mode 100644 index 0000000..c470016 --- /dev/null +++ b/src/services/ai-kurzy/kurzy.service.js @@ -0,0 +1,105 @@ +import { db } from '../../config/database.js'; +import { kurzy } from '../../db/schema.js'; +import { eq, sql, asc } from 'drizzle-orm'; +import { NotFoundError } from '../../utils/errors.js'; + +export const getAllKurzy = async () => { + const result = await db + .select({ + id: kurzy.id, + nazov: kurzy.nazov, + typKurzu: kurzy.typKurzu, + popis: kurzy.popis, + cena: kurzy.cena, + maxKapacita: kurzy.maxKapacita, + aktivny: kurzy.aktivny, + farba: kurzy.farba, + createdAt: kurzy.createdAt, + registraciiCount: sql`(SELECT COUNT(*) FROM registracie WHERE kurz_id = ${kurzy.id})::int`, + }) + .from(kurzy) + .orderBy(asc(kurzy.nazov)); + + return result; +}; + +export const getKurzById = async (id) => { + const [kurz] = await db + .select() + .from(kurzy) + .where(eq(kurzy.id, id)) + .limit(1); + + if (!kurz) { + throw new NotFoundError('Kurz nenájdený'); + } + + return kurz; +}; + +export const createKurz = async (data) => { + const [newKurz] = await db + .insert(kurzy) + .values({ + nazov: data.nazov, + typKurzu: data.typKurzu, + popis: data.popis || null, + cena: data.cena, + maxKapacita: data.maxKapacita || null, + aktivny: data.aktivny !== undefined ? data.aktivny : true, + farba: data.farba || null, + }) + .returning(); + + return newKurz; +}; + +export const updateKurz = async (id, data) => { + await getKurzById(id); + + const updateData = { + nazov: data.nazov, + typKurzu: data.typKurzu, + popis: data.popis !== undefined ? data.popis : undefined, + cena: data.cena, + maxKapacita: data.maxKapacita !== undefined ? data.maxKapacita : undefined, + aktivny: data.aktivny !== undefined ? data.aktivny : undefined, + farba: data.farba !== undefined ? data.farba : undefined, + updatedAt: new Date(), + }; + + Object.keys(updateData).forEach(key => { + if (updateData[key] === undefined) { + delete updateData[key]; + } + }); + + const [updated] = await db + .update(kurzy) + .set(updateData) + .where(eq(kurzy.id, id)) + .returning(); + + return updated; +}; + +export const deleteKurz = async (id) => { + await getKurzById(id); + await db.delete(kurzy).where(eq(kurzy.id, id)); + return { success: true, message: 'Kurz bol odstránený' }; +}; + +export const getKurzyStats = async () => { + const [stats] = await db + .select({ + totalKurzy: sql`(SELECT COUNT(*) FROM kurzy)::int`, + aktivneKurzy: sql`(SELECT COUNT(*) FROM kurzy WHERE aktivny = true)::int`, + totalUcastnici: sql`(SELECT COUNT(*) FROM ucastnici)::int`, + totalRegistracie: sql`(SELECT COUNT(*) FROM registracie)::int`, + zaplateneRegistracie: sql`(SELECT COUNT(*) FROM registracie WHERE zaplatene = true)::int`, + absolvovaneRegistracie: sql`(SELECT COUNT(*) FROM registracie WHERE stav = 'absolvoval')::int`, + }) + .from(sql`(SELECT 1) AS dummy`); + + return stats; +}; diff --git a/src/services/ai-kurzy/registracie.service.js b/src/services/ai-kurzy/registracie.service.js new file mode 100644 index 0000000..b19f357 --- /dev/null +++ b/src/services/ai-kurzy/registracie.service.js @@ -0,0 +1,234 @@ +import { db } from '../../config/database.js'; +import { kurzy, ucastnici, registracie, prilohy } from '../../db/schema.js'; +import { and, desc, eq, sql } from 'drizzle-orm'; +import { NotFoundError } from '../../utils/errors.js'; + +export const getAllRegistracie = async (kurzId = null) => { + const conditions = kurzId ? [eq(registracie.kurzId, kurzId)] : []; + + const result = await db + .select({ + id: registracie.id, + kurzId: registracie.kurzId, + ucastnikId: registracie.ucastnikId, + datumOd: registracie.datumOd, + datumDo: registracie.datumDo, + formaKurzu: registracie.formaKurzu, + pocetUcastnikov: registracie.pocetUcastnikov, + fakturaCislo: registracie.fakturaCislo, + fakturaVystavena: registracie.fakturaVystavena, + zaplatene: registracie.zaplatene, + stav: registracie.stav, + poznamka: registracie.poznamka, + createdAt: registracie.createdAt, + kurzNazov: kurzy.nazov, + kurzTyp: kurzy.typKurzu, + ucastnikMeno: ucastnici.meno, + ucastnikPriezvisko: ucastnici.priezvisko, + ucastnikEmail: ucastnici.email, + ucastnikFirma: ucastnici.firma, + }) + .from(registracie) + .leftJoin(kurzy, eq(registracie.kurzId, kurzy.id)) + .leftJoin(ucastnici, eq(registracie.ucastnikId, ucastnici.id)) + .where(conditions.length > 0 ? and(...conditions) : undefined) + .orderBy(desc(registracie.datumOd), desc(registracie.createdAt)); + + return result; +}; + +export const getRegistraciaById = async (id) => { + const [reg] = await db + .select({ + id: registracie.id, + kurzId: registracie.kurzId, + ucastnikId: registracie.ucastnikId, + formaKurzu: registracie.formaKurzu, + pocetUcastnikov: registracie.pocetUcastnikov, + fakturaCislo: registracie.fakturaCislo, + fakturaVystavena: registracie.fakturaVystavena, + zaplatene: registracie.zaplatene, + stav: registracie.stav, + poznamka: registracie.poznamka, + createdAt: registracie.createdAt, + kurzNazov: kurzy.nazov, + kurzTyp: kurzy.typKurzu, + ucastnikMeno: ucastnici.meno, + ucastnikPriezvisko: ucastnici.priezvisko, + ucastnikEmail: ucastnici.email, + }) + .from(registracie) + .leftJoin(kurzy, eq(registracie.kurzId, kurzy.id)) + .leftJoin(ucastnici, eq(registracie.ucastnikId, ucastnici.id)) + .where(eq(registracie.id, id)) + .limit(1); + + if (!reg) { + throw new NotFoundError('Registrácia nenájdená'); + } + + return reg; +}; + +export const createRegistracia = async (data) => { + const [newReg] = await db + .insert(registracie) + .values({ + kurzId: data.kurzId, + ucastnikId: data.ucastnikId, + datumOd: data.datumOd ? new Date(data.datumOd) : null, + datumDo: data.datumDo ? new Date(data.datumDo) : null, + formaKurzu: data.formaKurzu || 'prezencne', + pocetUcastnikov: data.pocetUcastnikov || 1, + fakturaCislo: data.fakturaCislo || null, + fakturaVystavena: data.fakturaVystavena || false, + zaplatene: data.zaplatene || false, + stav: data.stav || 'registrovany', + poznamka: data.poznamka || null, + }) + .returning(); + + return newReg; +}; + +export const updateRegistracia = async (id, data) => { + await getRegistraciaById(id); + + const [updated] = await db + .update(registracie) + .set({ + ...data, + updatedAt: new Date(), + }) + .where(eq(registracie.id, id)) + .returning(); + + return updated; +}; + +export const deleteRegistracia = async (id) => { + await getRegistraciaById(id); + await db.delete(registracie).where(eq(registracie.id, id)); + return { success: true, message: 'Registrácia bola odstránená' }; +}; + +export const getCombinedTableData = async () => { + const result = await db + .select({ + id: registracie.id, + ucastnikId: ucastnici.id, + titul: ucastnici.titul, + meno: ucastnici.meno, + priezvisko: ucastnici.priezvisko, + email: ucastnici.email, + telefon: ucastnici.telefon, + firma: ucastnici.firma, + firmaIco: ucastnici.firmaIco, + firmaDic: ucastnici.firmaDic, + firmaIcDph: ucastnici.firmaIcDph, + firmaSidlo: ucastnici.firmaSidlo, + mesto: ucastnici.mesto, + ulica: ucastnici.ulica, + psc: ucastnici.psc, + kurzId: kurzy.id, + kurzNazov: kurzy.nazov, + kurzTyp: kurzy.typKurzu, + kurzFarba: kurzy.farba, + datumOd: registracie.datumOd, + datumDo: registracie.datumDo, + formaKurzu: registracie.formaKurzu, + pocetUcastnikov: registracie.pocetUcastnikov, + fakturaCislo: registracie.fakturaCislo, + fakturaVystavena: registracie.fakturaVystavena, + zaplatene: registracie.zaplatene, + stav: registracie.stav, + poznamka: registracie.poznamka, + createdAt: registracie.createdAt, + dokumentyCount: sql`(SELECT COUNT(*) FROM prilohy WHERE registracia_id = ${registracie.id})::int`, + }) + .from(registracie) + .innerJoin(ucastnici, eq(registracie.ucastnikId, ucastnici.id)) + .innerJoin(kurzy, eq(registracie.kurzId, kurzy.id)) + .orderBy(desc(registracie.datumOd), desc(registracie.createdAt)); + + return result; +}; + +export const updateField = async (registrationId, field, value) => { + const ucastnikFields = ['titul', 'meno', 'priezvisko', 'email', 'telefon', 'firma', 'firmaIco', 'firmaDic', 'firmaIcDph', 'firmaSidlo', 'mesto', 'ulica', 'psc']; + const registraciaFields = ['datumOd', 'datumDo', 'formaKurzu', 'pocetUcastnikov', 'fakturaCislo', 'fakturaVystavena', 'zaplatene', 'stav', 'poznamka', 'kurzId']; + const dateFields = ['datumOd', 'datumDo']; + + const [reg] = await db + .select({ ucastnikId: registracie.ucastnikId }) + .from(registracie) + .where(eq(registracie.id, registrationId)) + .limit(1); + + if (!reg) { + throw new NotFoundError('Registrácia nenájdená'); + } + + let processedValue = value; + if (dateFields.includes(field)) { + processedValue = value ? new Date(value) : null; + } + + if (ucastnikFields.includes(field)) { + await db + .update(ucastnici) + .set({ [field]: processedValue, updatedAt: new Date() }) + .where(eq(ucastnici.id, reg.ucastnikId)); + } else if (registraciaFields.includes(field)) { + await db + .update(registracie) + .set({ [field]: processedValue, updatedAt: new Date() }) + .where(eq(registracie.id, registrationId)); + } else { + throw new Error(`Unknown field: ${field}`); + } + + return { success: true }; +}; + +export const getPrilohyByRegistracia = async (registraciaId) => { + const result = await db + .select() + .from(prilohy) + .where(eq(prilohy.registraciaId, registraciaId)) + .orderBy(desc(prilohy.createdAt)); + + return result; +}; + +export const createPriloha = async (data) => { + const [newPriloha] = await db + .insert(prilohy) + .values({ + registraciaId: data.registraciaId, + nazovSuboru: data.nazovSuboru, + typPrilohy: data.typPrilohy || 'ine', + cestaKSuboru: data.cestaKSuboru, + mimeType: data.mimeType || null, + velkostSuboru: data.velkostSuboru || null, + popis: data.popis || null, + }) + .returning(); + + return newPriloha; +}; + +export const deletePriloha = async (id) => { + const [priloha] = await db + .select() + .from(prilohy) + .where(eq(prilohy.id, id)) + .limit(1); + + if (!priloha) { + throw new NotFoundError('Príloha nenájdená'); + } + + await db.delete(prilohy).where(eq(prilohy.id, id)); + return { success: true, filePath: priloha.cestaKSuboru }; +}; diff --git a/src/services/ai-kurzy/ucastnici.service.js b/src/services/ai-kurzy/ucastnici.service.js new file mode 100644 index 0000000..e386ab7 --- /dev/null +++ b/src/services/ai-kurzy/ucastnici.service.js @@ -0,0 +1,88 @@ +import { db } from '../../config/database.js'; +import { ucastnici } from '../../db/schema.js'; +import { eq, sql, asc } from 'drizzle-orm'; +import { NotFoundError } from '../../utils/errors.js'; + +export const getAllUcastnici = async () => { + const result = await db + .select({ + id: ucastnici.id, + titul: ucastnici.titul, + meno: ucastnici.meno, + priezvisko: ucastnici.priezvisko, + email: ucastnici.email, + telefon: ucastnici.telefon, + firma: ucastnici.firma, + firmaIco: ucastnici.firmaIco, + firmaDic: ucastnici.firmaDic, + firmaIcDph: ucastnici.firmaIcDph, + firmaSidlo: ucastnici.firmaSidlo, + mesto: ucastnici.mesto, + ulica: ucastnici.ulica, + psc: ucastnici.psc, + createdAt: ucastnici.createdAt, + registraciiCount: sql`(SELECT COUNT(*) FROM registracie WHERE ucastnik_id = ${ucastnici.id})::int`, + }) + .from(ucastnici) + .orderBy(asc(ucastnici.priezvisko), asc(ucastnici.meno)); + + return result; +}; + +export const getUcastnikById = async (id) => { + const [ucastnik] = await db + .select() + .from(ucastnici) + .where(eq(ucastnici.id, id)) + .limit(1); + + if (!ucastnik) { + throw new NotFoundError('Účastník nenájdený'); + } + + return ucastnik; +}; + +export const createUcastnik = async (data) => { + const [newUcastnik] = await db + .insert(ucastnici) + .values({ + titul: data.titul || null, + meno: data.meno, + priezvisko: data.priezvisko, + email: data.email, + telefon: data.telefon || null, + firma: data.firma || null, + firmaIco: data.firmaIco || null, + firmaDic: data.firmaDic || null, + firmaIcDph: data.firmaIcDph || null, + firmaSidlo: data.firmaSidlo || null, + mesto: data.mesto || null, + ulica: data.ulica || null, + psc: data.psc || null, + }) + .returning(); + + return newUcastnik; +}; + +export const updateUcastnik = async (id, data) => { + await getUcastnikById(id); + + const [updated] = await db + .update(ucastnici) + .set({ + ...data, + updatedAt: new Date(), + }) + .where(eq(ucastnici.id, id)) + .returning(); + + return updated; +}; + +export const deleteUcastnik = async (id) => { + await getUcastnikById(id); + await db.delete(ucastnici).where(eq(ucastnici.id, id)); + return { success: true, message: 'Účastník bol odstránený' }; +};