londi-finding-matching.js

mail@pastecode.io avatar
unknown
plain_text
2 years ago
6.2 kB
2
Indexable
Never
import {
  diagnosticResults,
  testTimes,
  categories,
  education,
} from "./londi-constants.js";
import {
  getTestCategory,
  londiSubtests,
  londiData,
} from "./londi-suggestions.js";
import _ from "lodash";

export const fundingData =
  require("../assets/LONDI Förderalgorithmus aktuell.json").Foerderalgorithmus_MC_korrigier;

const COLUMN_HEADER_ID = "C";

/* 
this method calculates the child inputs + test results and returns a list of funding options
*/
const dummy = {
  schoolGrade: 1,
  testTime: 2, //see enum testTimes
  germanSecondaryLanguage: true,
  screenResultsEstimated: false, //false to use blue/yellow/green results, or true if using true/false results (1 or 0)
  screeningResults: [
    { category: categories.Reading, result: 1 }, //result value is either from diagnosticResults or (1 / 0)
    { category: categories.Writing, result: 2 },
    { category: categories.Math, result: 3 },
  ],
  selectedTests: [
    {
      category: categories.Reading,
      testId: 61,
      results: [
        { competenceLevel: 1, title: "Mengenerfassung", result: 20 },
        { competenceLevel: 1, title: "Zahlerfassung ", result: 20 },
        { competenceLevel: 1, title: "Mengenerfassung", result: 20 },
        { competenceLevel: 3, title: "Addition/Subtraktion", result: 20 },
      ],
    },
    {
      category: categories.Math,
      testId: 29,
      results: [{ competenceLevel: 1, title: "Summe DEMAT 5+", result: 20 }],
    },
  ],
};

export const getFundingMatching = (data) => {
  console.log("getFundingMatching", data);
  const categoriesResult = [];
  const results = [];
  if (
    data.screeningResults.find(
      (x) => x.testId && x.category === categories.Reading
    )
  ) {
    categoriesResult.push(categories.Reading);
  }
  if (
    data.screeningResults.find(
      (x) => x.testId && x.category === categories.Writing
    )
  ) {
    categoriesResult.push(categories.Writing);
  }
  if (
    data.screeningResults.find(
      (x) => x.testId && x.category === categories.Math
    )
  ) {
    categoriesResult.push(categories.Math);
  }


  categoriesResult.forEach((category) => {
    //calculate the profile for each category
    //const fundingProfiles = getFundingProfiles(data.selectedTests);

    //filter the funding data
    let filterEducationColumn = "";
    switch (data.education) {
      case education.Elementary:
        filterEducationColumn = "CN";
        break;
      case education.Middle:
        filterEducationColumn = "CO";
        break;
      case education.High:
        filterEducationColumn = "CP";
        break;
      default:
        throw new Error("invalid education area");
    }

    //filter by areas
    const categoryFilterColumns = [];
    switch (category) {
      case categories.Reading:
        categoryFilterColumns.push("BZ");
        break;
      case categories.Writing:
        categoryFilterColumns.push("CA");
        break;
      case categories.Math:
        categoryFilterColumns.push("CB");
        break;
      default:
        throw new Error("invalid category");
    }

    const educationFilter = fundingData.filter(
      (x) => x[filterEducationColumn] === "ja"
    );
    const filteredFundingData = [];
    categoryFilterColumns.forEach((col) => {
      filteredFundingData.push(
        ...educationFilter.filter(
          (x) =>
            x[col] === "ja" &&
            !_.some(
              filteredFundingData,
              (y) => y[COLUMN_HEADER_ID] === x[COLUMN_HEADER_ID]
            ) //don't add duplicates
        )
      );
    });

    //format the results
    const catResults = filteredFundingData.map((x) => {
      return {
        title: x["G"],
        subtitle: x["H"],
        publisher: x["X"],
        year: x["V"],
        authors: getAuthors(x),
        link: x["Z"],
      };
    });

    results.push({ category, results: catResults });
  });

  return results;
};

const getAuthors = (x) => {
  const authors = [];
  for (let idx = "I"; idx < "U"; idx = stepOneLetter(stepOneLetter(idx))) {
    if (x[idx]?.trim().length > 0) {
      authors.push(`${x[idx]} ${x[stepOneLetter(idx)]}`);
    }
  }
  return authors;
};

const stepOneLetter = (letter) => {
  return String.fromCharCode(letter.charCodeAt(0) + 1);
};

const levelWeight = (level) => {
  switch (level) {
    case 1:
      return 4;
    case 2:
      return 3;
    case 3:
      return 2;
    case 4:
      return 1;
    default:
      throw new Error("invalid level");
  }
};

const getFundingProfiles = (data) => {
  const fundingProfiles = {};
  const results = {};
  data.selectedTests.forEach((test) => {
    const category = test.category;
    if (!fundingProfiles[category]) {
      fundingProfiles[category] = {};
      results[category] = {};
    }
    //get the funding profile for the test, first get recodedPR
    for (let level = 1; level <= 4; level++) {
      const resultsPerLevel = test.results.filter(
        (x) => x.competenceLevel === level
      );
      if (resultsPerLevel.length > 0) {
        const resultsAverage = _.meanBy(resultsPerLevel, "result"); //find the average result for this level
        const recodedPR = recodePR(resultsAverage);
        fundingProfiles[category][level].recodedPR = recodedPR;
      }
    }
    //calculate for leve 2 if missing values
    if (!fundingProfiles[category][2]) {
      const pr1and3 =
        fundingProfiles[category][1]?.recodedPR +
        fundingProfiles[category][3]?.recodedPR;
      if (pr1and3 > 0) {
        fundingProfiles[category][2].recodedPR = pr1and3 / 2;
      }
    }

    //calculate the weight
    for (let level = 1; level <= 4; level++) {
      const weight = levelWeight(level);
      const weightedPR = fundingProfiles[category][level].recodedPR * weight;

      fundingProfiles[category][level].weightedPR = weightedPR;
    }

    //caculate the sum profile
    //get weightedPR for all levels
    const allWeightedPR = _.sumBy(fundingProfiles[category], "weightedPR");
    results[category] = allWeightedPR;
  });
  return results;
};

const recodePR = (pr) => {
  if (pr < 11) {
    return 3;
  }
  if (pr < 21) {
    return 2;
  }
  if (pr < 31) {
    return 1;
  }
  return 0;
};