Search code examples
javascriptobjecttreetreeview

Chart of accounts to tree view


I have this string it represent a chart of accounts

     "1: Comptes de capitaux
      10\. Capital et Réserves.
      101\. Capital.
      1011\. Capital souscrit - non appelé.
      1012\. Capital souscrit - appelé, non versé.
      1013\. Capital souscrit - appelé, versé.
      10131\. Capital non amorti.
      10132\. Capital amorti.
      1018\. Capital souscrit soumis à une réglementation particulière.
      105\. Ecarts de réévaluation.
      108\. Compte de l'exploitant. "

I want this output :

    "1":
      { id:"1",
        accountName: "Comptes de capitaux",  
        children:{
         id:"10",
         accountName: "Capital et Réserves" ,
           children:{
             id:"101",
             accountName:"Capital",
               children: {
                 id:"1011",
                 accountName:"Capital souscrit - non appelé",
                 children: {...}  
               },{
                   id:"1012",
                   accountName:"Capital souscrit - appelé, non versé",
                   children: {...}
                 },...
                 },{
                   id:"105",
                   accountName:"Ecarts de réévaluation",
                   children: {}
                 },{...}  
           }
       }

The solution should correctly create the tree structure with the parent-child relationships based on the account ID this my solution and is always wrong it does not correctly create the tree structure above can you provide me the right answer or the error i have commited in my code

    function createChartOfAccountsTree(input) {
      // Split the input by line
      const lines = input.split("\n");
      // Create an object to store the accounts
      let accounts = {};
      // Loop through each line
      for (let i = 0; i < lines.length; i++) {
        // Split the line by space
        let parts = lines[i].split(" ");
        // Extract the ID and account name
        let id = parts[0];
        let accountName = parts.slice(1).join(" ");
        // remove the dot from account name
        accountName = accountName.replace(".","");
        // Create an account object
        let account = {
          id,
          accountName,
          children: {}
          };
        // Check if the account is a child of an existing account
        let parentId = id.slice(0, -1);
        let parent = accounts[parentId];
        if (parent) {
        // If the account has a parent, add it as a child
        parent.children[id] = account;
        } else {
          // If the account does not have a parent, it's a top level account
          accounts[id] = account;
       }
     }
    return accounts;
   }

console.log(createChartOfAccountsTree("1 : Comptes de capitaux\n10. Capital et    Réserves.\n101.Capital.\n1011. Capital souscrit - non appelé.\n1012. Capital souscrit - appelé, non versé.\n1013. Capital souscrit - appelé, versé.\n10131. Capital non amorti.\n10132. Capital amorti.\n1018. Capital souscrit soumis à une réglementation particulière.\n105. Ecarts de réévaluation.\n108. Compte de l'exploitant. ")); ```

Solution

  • There are a few issues:

    • The input seems to not have the same format on each line. In the example, the first line has a colon after the number (or a space and a colon -- as in your code), while other lines have a point after the number.

    • In either case, your current code does not remove those delimiters when they come right after the initial number. So there is no child-parent match when you just remove the final character from the id to identify the parent -- as you only remove that point or colon (when there is no space before it). If the input format is really that varying, then you could use a regular expression to identify the two parts in each line.

    • The code seems to want children to be a plain object whose keys are id values, but your desired output section does not specify such keys -- it represents children as if it is an array but with an invalid syntax.

    • As you want to identify each parent with accounts[parentId], you must make sure that every entry is logged in accounts, not just the top level. So the else should be revised. Maybe use a separate variable that serves for logging the top level accounts only.

    Here is your code with the above issues handled:

    function createChartOfAccountsTree(input) {
      // Split the input by line, and immediately identify 
      //   the numeric prefix, and exclude final point
      const lines = input.matchAll(/^(\d+)[ .:]+(.*?)\.?[ ]*$/gm);
      // Create an object to store all the accounts
      const accounts = {};
      // ...and one for the top-level accounts
      const top = {};
      // Loop through each line, grabbing the parts
      for (const [, id, accountName] of lines) {
        // Create an account object
        let account = {
          id,
          accountName,
          children: {}
        };
        // Check if the account is a child of an existing account
        let parentId = id.slice(0, -1);
        let parent = accounts[parentId];
        if (parent) {
          // If the account has a parent, add it as a child
          parent.children[id] = account;
        } else {
          // If the account does not have a parent, it's a top level account
          top[id] = account;
        }
        // Log all accounts:
        accounts[id] = account;
      }
      return top;
    }
    
    const input = `1: Comptes de capitaux
    10. Capital et Réserves.
    101. Capital.
    1011. Capital souscrit - non appelé.
    1012. Capital souscrit - appelé, non versé.
    1013. Capital souscrit - appelé, versé.
    10131. Capital non amorti.
    10132. Capital amorti.
    1018. Capital souscrit soumis à une réglementation particulière.
    105. Ecarts de réévaluation.
    108. Compte de l'exploitant. `;
    
    console.log(createChartOfAccountsTree(input));