personnal/ecole/src/services/parcoursService.js

278 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// services/parcoursService.js
const { db } = require("../db/db-connect");
const logger = require("../utils/logger");
const globalService = require("../services/globalService");
/**
* Récupère un parcours par son numéro (avec expand utiles)
*/
async function getParcoursByNumParcours(numParcours) {
const criteria = {
filter: `numParcours='${numParcours}'`,
expand: [
"dernierUtilisateur.region",
"contrat",
"contrat.client",
"contrat.intermediaire"
].join(",")
};
return globalService.fetchInfoByCriteria("parcours", criteria);
}
/**
* Full list (batch côté PocketBase). | Fetch l'ensemble de la BD via chunk "batch"
* avec getFullList(collection, batchSize, options)
*/
async function getParcoursFullList({ filter, sort, expand, fields, batch = 500 }) {
const options = {
sort: sort || "-created",
};
// Ajouter expand si défini
if (expand) {
options.expand = expand;
}
// Ajouter fields si défini
if (fields) {
options.fields = fields;
}
// Ajouter filter SEULEMENT s'il n'est pas vide (Pocketbase 0.7 rejette les filtres vides)
if (filter && filter.trim() !== "") {
options.filter = filter;
}
// getFullList(collection, batchSize, options)
return db.records.getFullList("parcours", batch, options);
}
/**
* Pagination multi-régions + filtres/tri optionnels (server-side DataTables)
* Parcours une seule fois db par requête
* @param {string[]} regions
* @param {number} page
* @param {number} perPage
* @param {{filter?: string, sort?: string}} opts
*/
async function getParcoursByRegionsPage(regions = [], page = 1, perPage = 10, opts = {}) {
try {
let regFilter = "";
if (Array.isArray(regions) && regions.length > 0) {
const ors = regions.map(r => `dernierUtilisateur.region.nom = "${r}"`);
regFilter = `(${ors.join(" || ")})`;
}
const filter = [regFilter, opts.filter].filter(Boolean).join(" && ");
/**
* Récupération des parcours avec expands nécessaires
* Note: L'expand de contrat.client ne fonctionne pas toujours,
* d'où la nécessité d'un fallback dans le contrôleur
*/
const list = await db.records.getList("parcours", page, perPage, {
sort: opts.sort || "-created",
filter: filter || "",
expand: [
"contrat",
"contrat.client",
"contrat.intermediaire",
"dernierUtilisateur.region"
].join(","),
});
return {
page: list.page,
perPage: list.perPage,
totalItems: list.totalItems,
totalPages: list.totalPages,
items: list.items,
};
}
catch (error) {
logger.log('error', error);
throw error;
}
}
/**
* Création d'un parcours vide
*/
async function createNewEmptyParcours(numParcours) {
try {
const data = { ["numParcours"]: numParcours };
const record = await db.records.create("parcours", data);
if (record) {
return record.id;
} else {
return null;
}
}
catch (error) {
logger.log("error", error);
return null;
}
}
/**
* MAJ d'un champ d'un parcours
*/
async function updateFieldValueParcours(id, field, value) {
try {
const data = { [field]: value };
const record = await db.records.update("parcours", id, data);
if (record) {
return record.id;
} else {
return null;
}
}
catch (error) {
logger.log("error", error);
return null;
}
}
/**
* Génère le prochain numéro de parcours
*/
async function getNewParcoursNumber() {
try {
const list = await db.records.getList("parcours", 1, 1, { sort: "-numParcours" });
const last = list?.items?.[0];
if (!last?.numParcours) return null;
const numericValue = parseInt(String(last.numParcours).substring(1), 10);
if (Number.isNaN(numericValue)) return null;
const next = numericValue + 1;
return "P" + next.toString().padStart(9, "0");
}
catch (error) {
logger.log("error", error);
return null;
}
}
// --- Section détails profonds (contrat + fiche produit) --- //
/**
* Récupère un parcours (via numParcours) avec les expands utiles pour détails.
*/
async function getParcoursForDetails(numParcours) {
try {
const list = await db.records.getList("parcours", 1, 1, {
filter: `numParcours='${numParcours}'`,
expand: [
"contrat",
"contrat.client",
"contrat.intermediaire",
"dernierUtilisateur.region"
].join(","),
});
return list?.items?.[0] || null;
}
catch (e) {
logger.log("error", e);
return null;
}
}
/**
* Mappe un libellé produit vers la collection PocketBase (à ajuster si changement de parcours).
*/
function mapProduitToCollection(produitRaw = "") {
const p = String(produitRaw || "").trim().toUpperCase();
const map = {
"TPPC": "tppc",
"RC": "rc",
"FAC": "fac",
};
return map[p] || null;
}
/**
* Récupère la fiche produit pour un contrat donné.
* On tente d'abord par relation "contrat = contratId" si elle existe,
* sinon fallback par "numContrat = x" si jamais la fiche stocke le numéro.
*/
async function getProduitRecordForContrat(contrat, opts = {}) {
try {
if (!contrat) return null;
const collection = mapProduitToCollection(contrat.produit);
if (!collection) return null;
// Tente via une relation directe "contrat" (champ le plus propre)
try {
const record = await db.records.getFirstListItem(collection, `contrat='${contrat.id}'`, {
});
if (record) return record;
}
catch (_) { /* ignore, on tente le fallback */ }
// Fallback
if (contrat.numContrat) {
try {
const record = await db.records.getFirstListItem(collection, `numContrat='${contrat.numContrat}'`, {});
if (record) return record;
}
catch (_) { /* ignore */ }
}
return null;
} catch (e) {
logger.log("error", e);
return null;
}
}
/**
* reformatage texte - a virer
*/
function escPB(s = "") {
return String(s).replace(/"/g, '\\"');
}
/**
* Détails complets: parcours + contrat + fiche produit
*/
async function getDeepDetailsByNumParcours(numParcours) {
try {
const filter = `numParcours = "${escPB(numParcours)}"`;
const list = await db.records.getList("parcours", 1, 1, {
filter,
expand: [
"contrat",
"contrat.client",
"contrat.intermediaire",
"dernierUtilisateur.region",
// produit lié
"contrat.tppc",
"contrat.rc",
"contrat.fac",
// sous-relations TPPC
"contrat.tppc.tarif",
"contrat.tppc.projet",
].join(","),
});
return list?.items?.[0] || null;
} catch (e) {
logger.log("error", e);
return null;
}
}
module.exports = {
getNewParcoursNumber,
getParcoursByNumParcours,
createNewEmptyParcours,
updateFieldValueParcours,
getParcoursByRegionsPage,
getParcoursFullList,
getParcoursForDetails,
getProduitRecordForContrat,
getDeepDetailsByNumParcours,
mapProduitToCollection,
};