Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

Hi, I’m stuck with the “build-a-cash-register” test: tests #14 through 19 won’t pass although when I test them individually manually with the appropriate set of values for each scenario, I get the expected result.
How can I get details about why my code won’t pass?

Your code so far

<!-- file: index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document title</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <header>
      <h1>Cash Register Project</h1>
    </header>
    <main>
      <div id="change-due">

      </div>
      <label for="cash">Enter cash amount from customer</label>
      <input id="cash" name ="cash" type="number"></input>
      <button id="purchase-btn">Check amount</button>
      <div id="cost-block">
        <p id="price-element"></p>
      </div>
      <div id="drawer-block">
        <h3>Change in drawer:</h3>
      </div>
    </main>
  	<script src="./script.js"></script>
  </body>
</html> 

/* file: styles.css */

/* file: script.js */
const changeElement = document.getElementById("change-due");
const cashElement = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const priceElement = document.getElementById("price-element");
const drawerBlock = document.getElementById("drawer-block");

const currencyInfo = [
  ["Pennies", 0.01],
  ["Nickels", 0.05],
  ["Dimes", 0.1],
  ["Quarters", 0.25],
  ["Ones", 1],
  ["Fives", 5],
  ["Tens", 10],
  ["Twenties", 20],
  ["Hundreds", 100]
];

let price = 1.87;
let cid = cid = [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100]
];

let cid2 = [];
let cash = 0;
let change = 0;
let balance = 0;
let dt = 0;

const cidMerge = () => {
  let merge = [];
  for (let i = 0; i<= cid.length -1; ++i) {
    merge[i] = [...cid[i], ...currencyInfo[i]];
  }
  return merge;
} 

const round = (num, dec) => parseFloat(num.toFixed(dec));

const drawerTotal = () => round(cid2.reduce((acc, el) => acc + el[3], 0), 2);

const changeTotal = () => round(cid2.reduce((acc, el) => acc + el[4], 0), 2);

const cleanChangeElement = () => {
  changeElement.innerHTML = ""; 
  cid2.forEach((level) => {
    level[4] = 0;
  });
};

const initialiseValues = () => {
  cid2 = cidMerge();
  console.log(cid2);
  priceElement.innerText = `Total: $${price}`;

  cid2.forEach((index) => {
    drawerBlock.innerHTML += `<p class="drawer-item">${index[2]}: $${index[1]}</p>`;
  });

  cleanChangeElement();
}; 

const getLevel = (amount) => {
  let i = cid2.length - 1;
  let found = false;
  while (i >= 0 && !found) {
    if (amount >= cid2[i][3]) {
      found = true;
      return i; 
    }
    --i;
  }
  return 0;
}; 

const checkChange = (amount, level) => {
  const levelValue = cid2[level][3];
  const inDrawer = cid2[level][1]; 
  const q1 = Math.floor(amount / levelValue);
  const r1 = round(amount % levelValue, 2);  
  const q2 = Math.floor(inDrawer / levelValue);
  const loadedValue = Math.min(q1, q2) * levelValue;
  cid2[level][4] = loadedValue;
  if (level != 0) {
    checkChange(round(amount - loadedValue, 2), level - 1);
  } else {
    const ct = changeTotal();
    if (ct < change) {
      changeElement.innerHTML = "Status: INSUFFICIENT_FUNDS";
      return;
    } else if (ct === dt) {
      changeElement.innerHTML = "Status: CLOSED";    
    } else {
      changeElement.innerHTML = "Status: OPEN";    
    }
    for (let i = cid2.length - 1; i >= 0; --i) { 
      if (cid2[i][4] !== 0) {
        changeElement.innerHTML += `<p class="change-due">${cid2[i][0]}: $${cid2[i][4]}</p>`;
      };
    };
  }
};

purchaseBtn.addEventListener("click", () => {
  cleanChangeElement();
  cash = Number(cashElement.value);
  if (!cash) {
    alert("Please select customer cash amount");
    return;
  }

  if (cash < 0 || round(cash, 3) !== round(cash, 2)) {
    alert("Please select a positive value with 2 decimals maximum");
    return;
  }
  
  change = round(cash - price, 2);
  dt = drawerTotal();
  balance = round(dt - change, 2);
  if (change < 0) {
    alert("Customer does not have enough money to purchase the item");
  } else if (change === 0) {
    changeElement.innerHTML = "No change due - customer paid with exact cash";
  } else if (balance < 0) {
    changeElement.innerHTML = "Status: INSUFFICIENT_FUNDS"
  } else {
    checkChange(change, getLevel(change))
  }
});

initialiseValues();

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36

Challenge Information:

Build a Cash Register Project - Build a Cash Register

you may want to fix this

you should not have these variables in the global scope.

Hello IL. Thank you very much for your reply and advice. I’ve updated my code so as to get rid of every global variable but cid2. Unfortunately, it has not helped the code to pass the tests #14 through 19. Any clue?
Here’s the updated JS code (HTML remains unchanged):

const changeElement = document.getElementById("change-due");
const cashElement = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const priceElement = document.getElementById("price-element");
const drawerBlock = document.getElementById("drawer-block");

const currencyInfo = [
  ["Pennies", 0.01],
  ["Nickels", 0.05],
  ["Dimes", 0.1],
  ["Quarters", 0.25],
  ["Ones", 1],
  ["Fives", 5],
  ["Tens", 10],
  ["Twenties", 20],
  ["Hundreds", 100]
];

let price = 1.87;
let cid  = [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100]
];

let cid2 = [];

const cidMerge = () => {
  let merge = [];
  for (let i = 0; i<= cid.length -1; ++i) {
    merge[i] = [...cid[i], ...currencyInfo[i]];
  }
  return merge;
} 

const round = (num, dec) => parseFloat(num.toFixed(dec));

const drawerTotal = () => round(cid2.reduce((acc, el) => acc + el[3], 0), 2);

const changeTotal = () => round(cid2.reduce((acc, el) => acc + el[4], 0), 2);

const cleanChangeElement = () => {
  changeElement.innerHTML = ""; 
  cid2.forEach((level) => {
    level[4] = 0;
  });
};

const initialiseValues = () => {
  cid2 = cidMerge();
  //console.log(cid2);
  priceElement.innerText = `Total: $${price}`;

  cid2.forEach((index) => {
    drawerBlock.innerHTML += `<p class="drawer-item">${index[2]}: $${index[1]}</p>`;
  });

  cleanChangeElement();
}; 

const getLevel = (amount) => {
  let i = cid2.length - 1;
  let found = false;
  while (i >= 0 && !found) {
    if (amount >= cid2[i][3]) {
      found = true;
      return i; 
    }
    --i;
  }
  return 0;
}; 

const checkChange = (amount, level, drawer) => {
  const levelValue = cid2[level][3];
  const inDrawer = cid2[level][1]; 
  const q1 = Math.floor(amount / levelValue);
  //const r1 = round(amount % levelValue, 2);  
  const q2 = Math.floor(inDrawer / levelValue);
  const loadedValue = Math.min(q1, q2) * levelValue;
  cid2[level][4] = loadedValue;
  if (level != 0) {
    checkChange(round(amount - loadedValue, 2), level - 1, drawer);
  } else {
    const ct = changeTotal();
    if (ct < amount) {
      changeElement.innerHTML = "Status: INSUFFICIENT_FUNDS";
      return;
    } else if (ct === drawer) {
      changeElement.innerHTML = "Status: CLOSED";    
    } else {
      changeElement.innerHTML = "Status: OPEN";    
    }
    for (let i = cid2.length - 1; i >= 0; --i) { 
      if (cid2[i][4] !== 0) {
        changeElement.innerHTML += `<p class="change-due">${cid2[i][0]}: $${cid2[i][4]}</p>`;
      };
    };
  }
};

purchaseBtn.addEventListener("click", () => {
  cleanChangeElement();
  let cash = Number(cashElement.value);
  if (!cash) {
    alert("Please select customer cash amount");
    return;
  }

  if (cash < 0 || round(cash, 3) !== round(cash, 2)) {
    alert("Please select a positive value with 2 decimals maximum");
    return;
  }
  
  let change = round(cash - price, 2);
  let dt = drawerTotal();
  let balance = round(dt - change, 2);
  if (change < 0) {
    alert("Customer does not have enough money to purchase the item");
  } else if (change === 0) {
    changeElement.innerHTML = "No change due - customer paid with exact cash";
  } else if (balance < 0) {
    changeElement.innerHTML = "Status: INSUFFICIENT_FUNDS"
  } else {
    checkChange(change, getLevel(change), dt)
  }
});

initialiseValues();

if you have global variables that don’t reset between uses it will not work, the app is not restarted, the tests are like code added at the bottom of the editor

Ok I get it, now. Thanks a lot for the explanation.

Hi ILM. Thanks to your explanation, I’ve amended my code so as to get rid of every global variable. And it did improve the situation greatly as every test now passes except for test #17. I must acknowledge I don’t understand how test #16 could pass and test #17 would not . Scenario #16 is a particular case of scenario #17, isn’t it? Does that mean there would be a set of values which would not validate this test? Can you please help me out again?
Here’s the updated JS code (HTML has remained unchanged):

const changeElement = document.getElementById("change-due");
const cashElement = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const priceElement = document.getElementById("price-element");
const drawerBlock = document.getElementById("drawer-block");

const currencyInfo = [
  ["Pennies", 0.01],
  ["Nickels", 0.05],
  ["Dimes", 0.1],
  ["Quarters", 0.25],
  ["Ones", 1],
  ["Fives", 5],
  ["Tens", 10],
  ["Twenties", 20],
  ["Hundreds", 100]
];

let price = 1.87;
let cid  = [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100]
];

const round = (num, dec) => parseFloat(num.toFixed(dec));

const drawerTotal = (arr) => round(arr.reduce((acc, el) => acc + el[1], 0), 2);

const changeTotal = (arr) => round(arr.reduce((acc, el) => acc + el, 0), 2);

const resetChangeElement = () => {
  changeElement.innerHTML = ""; 
};

const initDrawerValues = () => {
  priceElement.innerText = `Total: $${price}`;
  for (let i = 0; i <= cid.length - 1; ++i) {
    drawerBlock.innerHTML += `<p class="drawer-item">${currencyInfo[i][0]}: $${cid[i][1]}</p>`;
  };
  resetChangeElement();
}; 

const getLevel = (amount) => {
  let i = currencyInfo.length - 1;
  let found = false;
  while (i >= 0 && !found) {
    if (amount >= currencyInfo[i][1]) {
      found = true;
      return i; 
    }
    --i;
  }
  return 0;
}; 

const checkChange = (amount, level, drawer, cdArr) => {
  const levelValue = currencyInfo[level][1];
  const inDrawer = cid[level][1]; 
  const q1 = Math.floor(amount / levelValue);
  const q2 = Math.floor(inDrawer / levelValue);
  const loadedValue = Math.min(q1, q2) * levelValue;
  cdArr[level] = loadedValue;
  if (level != 0) {
    checkChange(round(amount - loadedValue, 2), level - 1, drawer, cdArr);
  } else {
    const ct = changeTotal(cdArr);
    if (ct < amount) {
      changeElement.innerHTML = "Status: INSUFFICIENT_FUNDS";
      return;
    } else if (ct === drawer) {
      changeElement.innerHTML = "Status: CLOSED";    
    } else {
      changeElement.innerHTML = "Status: OPEN";    
    }
    for (let i = cdArr.length - 1; i >= 0; --i) { 
      if (cdArr[i] !== 0) {
        changeElement.innerHTML += `<p class="change-due">${cid[i][0]}: $${cdArr[i]}</p>`;
      };
    };
  }
};

purchaseBtn.addEventListener("click", () => {
  let changeDetails = [0, 0, 0, 0, 0, 0, 0, 0, 0];
  resetChangeElement();
  let cash = Number(cashElement.value);
  if (!cash) {
    alert("Please select customer cash amount");
    return;
  }
  if (cash < 0 || round(cash, 3) !== round(cash, 2)) {
    alert("Please select a positive value with 2 decimals maximum");
    return;
  }
  let change = round(cash - price, 2);
  let dt = drawerTotal(cid);
  let balance = round(dt - change, 2);
  if (change < 0) {
    alert("Customer does not have enough money to purchase the item");
  } else if (change === 0) {
    changeElement.innerHTML = "No change due - customer paid with exact cash";
  } else if (balance < 0) {
    changeElement.innerHTML = "Status: INSUFFICIENT_FUNDS"
  } else {
    checkChange(change, getLevel(change), dt, changeDetails);
  }
});

initDrawerValues();

You are failing this:

When price is 77.2 , the value in the #cash element is 100 , cid is [["PENNY", 0.04], ["NICKEL", 0.15], ["DIME", 0], ["QUARTER", 0], ["ONE", 7], ["FIVE", 5], ["TEN", 50], ["TWENTY", 280], ["ONE HUNDRED", 0]] , and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: INSUFFICIENT_FUNDS"

Your code is saying Status: OPEN TWENTY: $20 ONE: $2 NICKEL: $0.1 PENNY: $0.04

the change in this case would be $22.80, there are 66 cents less than what is needed in the change your code is giving out

Oh yes, you are right. This has been really helpful. Thanks a lot.