diff --git a/test/setCompanyEmail.ts b/test/setCompanyEmail.ts new file mode 100644 index 0000000..79d8929 --- /dev/null +++ b/test/setCompanyEmail.ts @@ -0,0 +1,94 @@ +/* + Corrige l'adresse électronique portée par la fiche société. + + POURQUOI CE CHEMIN EXISTE. `GET /setup/company` répond 403 à tout scope agent + (« open to admin users only »), et aucune route REST n'écrit les constantes + MAIN_INFO_SOCIETE_*. La fiche société n'est donc modifiable que par + l'interface — celle que l'opérateur emprunterait lui-même. + + POURQUOI ÇA COMPTE. Cette adresse s'imprime en en-tête de CHAQUE facture. Une + divergence entre la fiche et `static/config/company.json` ne se voit nulle part + dans l'ERP : elle ne se découvre qu'en lisant un PDF déjà parti chez le client. + C'est ainsi qu'elle a été trouvée le 2026-08-24. + + Un piège : la page de retour réaffiche la valeur soumise, qu'elle ait été + enregistrée ou non. On RECHARGE la page avant de vérifier — jamais la page de + retour. + + Usage : + deno run -A test/setCompanyEmail.ts --email contact@exemple.fr [--dry-run] +*/ +import "load_dotenv"; +import { chromium } from "playwright"; +import login from "./scripts/login.ts"; +import { assertSandbox } from "./scripts/guard.ts"; + +const argv = Deno.args; +const pick = (f: string, d = "") => (argv.includes(f) ? argv[argv.indexOf(f) + 1] : d); + +const email = pick("--email"); +const dryRun = argv.includes("--dry-run"); +// Le champ s'appelle simplement `mail` — PAS `MAIN_INFO_SOCIETE_MAIL`, malgré +// le nom de la constante qu'il alimente et malgré la convention suivie par +// tous ses voisins du même formulaire (ADDRESS, ZIP, TOWN…). Relevé sur la +// page le 2026-08-24 ; ne pas le « corriger » de mémoire. +const FIELD = 'input[name="mail"]'; + +if (!email || !email.includes("@")) { + console.error("--email est requis, et doit ressembler à une adresse"); + Deno.exit(2); +} + +const dolibarrAddress = assertSandbox(); +console.log(`cible : ${dolibarrAddress}`); +console.log(`email : ${email}`); + +const browser = await chromium.launch({ headless: true }); +const context = await browser.newContext({ locale: "fr-FR" }); +const page = await context.newPage(); + +try { + await login.doAdminLogin({ + page, + dolibarrAddress, + adminCredentials: { + username: Deno.env.get("DOLI_ADMIN_LOGIN") || "undefined", + password: Deno.env.get("DOLI_ADMIN_PASSWORD") || "undefined", + }, + }); + + const edit = `${dolibarrAddress}/admin/company.php?action=edit`; + await page.goto(edit); + const field = page.locator(FIELD); + if (await field.count() === 0) { + console.error("champ `mail` absent de /admin/company.php — droits insuffisants ?"); + Deno.exit(1); + } + const before = await field.inputValue(); + console.log(`avant : ${before || "(vide)"}`); + if (before === email) { + console.log("déjà à cette valeur, rien à faire."); + Deno.exit(0); + } + if (dryRun) { + console.log("\n--dry-run : rien n'est soumis."); + Deno.exit(0); + } + + await field.fill(email); + await page.locator('input[type="submit"][name="save"], input[type="submit"][value*="Enregistrer"]') + .first().click(); + await page.waitForLoadState("networkidle"); + + // On ne croit pas la page de retour : on recharge et on relit le champ. + await page.goto(edit, { waitUntil: "networkidle" }); + const after = await page.locator(FIELD).inputValue(); + console.log(`après : ${after || "(vide)"}`); + if (after !== email) { + console.error("ÉCHEC — la valeur relue ne correspond pas à celle soumise."); + Deno.exit(1); + } + console.log("ok — fiche société mise à jour et relue."); +} finally { + await browser.close(); +}