/// /** * Module Recherche & Analyse marché + champ prix revente au m² sur l'analyse financière. * * Les règles API doivent être assignées APRÈS fields.add(...): sinon le validateur ne voit * pas les champs (erreurs "unknown field user" / "failed to resolve field owner"). */ migrate( (app) => { const usersCol = app.findCollectionByNameOrId("users"); let usersId = ""; if (usersCol) { const a = usersCol.id != null && String(usersCol.id) !== "" ? usersCol.id : null; const b = usersCol.Id != null && String(usersCol.Id) !== "" ? usersCol.Id : null; usersId = String(a != null ? a : b != null ? b : "").trim(); } if (!usersId) { throw new Error("migration 1746100000: collection users introuvable ou id vide"); } function findExistingCollection(name) { try { return app.findCollectionByNameOrId(name); } catch (_) {} try { const all = app.findAllCollections(); const want = String(name).toLowerCase(); for (let i = 0; i < all.length; i++) { const c = all[i]; if (c && c.name && String(c.name).toLowerCase() === want) { return c; } } } catch (_) {} return null; } function loadOrCreate(name, factory) { const existing = findExistingCollection(name); if (existing != null) { return existing; } try { const col = factory(); app.save(col); return col; } catch (err) { const msg = String(err && err.value ? err.value : err && err.message ? err.message : err); if (msg.includes("unique") || msg.includes("Unique")) { const again = findExistingCollection(name); if (again != null) { return again; } } throw err; } } const ownRecords = '@request.auth.id != "" && user.id = @request.auth.id'; const authOnly = '@request.auth.id != ""'; function makeAnalysesSecteur() { const col = new Collection({ name: "analyses_secteur", type: "base" }); col.fields.add( new RelationField({ name: "user", required: true, collectionId: usersId, maxSelect: 1, cascadeDelete: true, }), ); col.fields.add(new TextField({ name: "ville", required: true })); col.fields.add(new TextField({ name: "notes", required: false })); col.listRule = ownRecords; col.viewRule = ownRecords; col.createRule = authOnly; col.updateRule = ownRecords; col.deleteRule = ownRecords; return col; } function makeNotesProspection() { const col = new Collection({ name: "notes_prospection", type: "base" }); col.fields.add( new RelationField({ name: "user", required: true, collectionId: usersId, maxSelect: 1, cascadeDelete: true, }), ); col.fields.add(new TextField({ name: "question", required: true })); col.fields.add(new TextField({ name: "reponse", required: false })); col.fields.add(new TextField({ name: "categorie", required: false })); col.listRule = ownRecords; col.viewRule = ownRecords; col.createRule = authOnly; col.updateRule = ownRecords; col.deleteRule = ownRecords; return col; } function makeGrillePrix() { const col = new Collection({ name: "grille_prix", type: "base" }); col.fields.add( new RelationField({ name: "user", required: true, collectionId: usersId, maxSelect: 1, cascadeDelete: true, }), ); col.fields.add( new SelectField({ name: "type_bien", required: true, maxSelect: 1, values: ["appartement", "maison", "immeuble"], }), ); col.fields.add( new SelectField({ name: "etat", required: true, maxSelect: 1, values: ["bon_etat", "a_renover", "travaux_lourds"], }), ); col.fields.add(new NumberField({ name: "prix_achat_m2", required: true })); col.fields.add(new NumberField({ name: "prix_revente_m2", required: true })); col.fields.add(new NumberField({ name: "marge_estimee_pct", required: false })); col.fields.add(new TextField({ name: "ville", required: false })); col.listRule = ownRecords; col.viewRule = ownRecords; col.createRule = authOnly; col.updateRule = ownRecords; col.deleteRule = ownRecords; return col; } loadOrCreate("analyses_secteur", makeAnalysesSecteur); loadOrCreate("notes_prospection", makeNotesProspection); loadOrCreate("grille_prix", makeGrillePrix); try { const af = findExistingCollection("analyses_financieres"); if (af == null) { /* rien à faire */ } else { let has = false; for (let i = 0; i < af.fields.length; i++) { if (af.fields.get(i).name === "prix_revente_m2") { has = true; break; } } if (!has && typeof NumberField !== "undefined") { af.fields.add(new NumberField({ name: "prix_revente_m2", min: 0 })); app.save(af); } } } catch (_) { /* schéma déjà à jour ou API différente */ } }, (app) => { for (const name of ["grille_prix", "notes_prospection", "analyses_secteur"]) { try { app.delete(app.findCollectionByNameOrId(name)); } catch (_) {} } }, );