// procurement-criteria.jsx — бібліотека шаблонів критеріїв оцінки закупівель
// (PIN/Екоклуб). Багаторазові шаблони: ваги (сума 100%), методи (бали/формула/
// pass-fail), рубрики балів. Зберігаються на бекенді (resource procurement-criteria).
// Відкривається як повноекранна панель із вкладки «План закупівель».
(function () {
const KINDS = [
{ key: "Services", uk: "Послуги" },
{ key: "Works", uk: "Роботи" },
{ key: "Goods", uk: "Товари / Матеріали" },
{ key: "", uk: "Будь-який тип" },
];
const kindUk = (k) => (KINDS.find(x => x.key === k) || {}).uk || "Будь-який тип";
const METHODS = [
{ key: "points", uk: "Бали (рубрика)" },
{ key: "formula", uk: "Формула (ціна)" },
{ key: "passfail", uk: "Pass / Fail" },
];
const methodUk = (m) => (METHODS.find(x => x.key === m) || {}).uk || m;
const rnd = () => Math.random().toString(36).slice(2, 7);
const blankRubric = (score) => ({ score, desc: "" });
const blankCriterion = () => ({ id: "cr-" + rnd(), name: "", weight: 0, method: "points", maxScore: 5, formula: "", rubric: [] });
const sumWeight = (cs) => (cs || []).reduce((a, c) => a + (Number(c.weight) || 0), 0);
// ── друк одного шаблону в окреме вікно ──
function printTemplate(t) {
const esc = (s) => String(s == null ? "" : s).replace(/[&<>]/g, ch => ({ "&": "&", "<": "<", ">": ">" }[ch]));
const rows = (t.criteria || []).map((c, i) => {
let body = "";
if (c.method === "points") {
body = "
" + (c.rubric || []).map(r => `| ${esc(r.score)} | ${esc(r.desc)} |
`).join("") + "
";
} else if (c.method === "formula") {
body = `${esc(c.formula)}
`;
} else {
body = "Pass / Fail
";
}
return `| ${i + 1} | ${esc(c.name)}${c.method === "points" && c.maxScore ? ` макс. ${esc(c.maxScore)} балів ` : ""} | ${esc(c.weight)}% | ${body} |
`;
}).join("");
const html = `Критерії оцінки — ${esc(t.name)}
Критерії оцінки пропозицій
${esc(t.name)} · ${esc(kindUk(t.kind))}${t.note ? " · " + esc(t.note) : ""}
| № | Критерій | Вага | Шкала / метод оцінки |
${rows}
Сумарна вага: ${sumWeight(t.criteria)}%