Build a Cash Register project

Hi!
I’m stuck with this project, when I run the tests, I get the following wrong:

When price is less than the value in the #cash element, total cash in drawer 
cid is greater than change due, individual denomination 
amounts make impossible to return needed change, and the 
#purchase-btn element is clicked, the value in the #change-due 
element should be "Status: INSUFFICIENT_FUNDS"

As shown in the image, my program gets that status, so I don’t know what’s going on.

This is my code:
HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta 
      name="vewport"
      content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="./styles.css">
    <title>Cash register project</title>
  </head>
  <body>
    <div class="container">
      <input value="20" type="number" id="cash">
      <div id="change-due"></div>
      <button id="purchase-btn">Purchase</button>
    </div>

    <script src="./script.js"></script>
  </body>
</html>

JavaScript

const cashInput = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const changeDueElement = document.getElementById("change-due");

/*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 price = 19.5;
let cid = [
  ['PENNY', 0],
  ['NICKEL', 0],
  ['DIME', 0],
  ['QUARTER', 0],
  ['ONE', 90],
  ['FIVE', 55],
  ['TEN', 20],
  ['TWENTY', 60],
  ['ONE HUNDRED', 100]
];

// function to update html element with needed change
const updateChangeDueElement = (change) => {
  if (change.every((noteOrCoin) => noteOrCoin === 0)) {
      changeDueElement.innerHTML = 
      `<p>Status: INSUFFICIENT_FUNDS</p>`;
      return;
  }
  for (let i = cid.length - 1; i >= 0; i--) {
    if (change[i] > 0) {
      changeDueElement.innerHTML += `<p>${cid[i][0]}: $${change[i]}</p>`
    }
  }
}

const isChangePossible = (changeDue, change) => {
  const c1 = change.reduce((acc, el) => acc + el, 0);
  return c1 >= changeDue;
}

// function to calculate change due
const getChange = (changeDue) => {
  // array with values per note/coin
  const notesAndCoins = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100]
  // array with needed change
  const change = [];

  for (let i = cid.length - 1; i >= 0; i--) {
    // how many of each do we have?
    let available = Number((cid[i][1] / notesAndCoins[i]).toFixed(2));
    // how many would we need?
    let needed = parseInt((changeDue / notesAndCoins[i]).toFixed(2))

    // calculate how many we need according with availability
    if (changeDue >= notesAndCoins[i] && available) {
      let toPush = 0;
      while (available > 0 && needed > 0) {
        cid[i][1] -= notesAndCoins[i];
        needed--;
        available--;
        toPush++;
      }

      // update change due
      changeDue -= notesAndCoins[i] * toPush;

      // push the number of notes/coins we need into the array
      change.unshift(Number((toPush * notesAndCoins[i]).toFixed(2)));
    } else {
      // if change is less than note/coin or there is not
      change.unshift(0);
    }
  }

  if (!isChangePossible(changeDue, change)) { 
    changeDueElement.innerHTML = 
      `<p>Status: INSUFFICIENT_FUNDS</p>`;
  } else { 
    updateChangeDueElement(change);
  }
}

purchaseBtn.addEventListener("click", () => {
  // check if #cash input is empty
  if (!cashInput.value) { return; }

  // use 2 digit precission in variables
  const cash = Number(cashInput.value).toFixed(2);
  const changeDue = Number(cash - price).toFixed(2);
  const cashInDrawer = Number(cid.reduce(
      (acc, elem) => acc + elem[1], 0
      ).toFixed(2));

  if (cash < price) {
    alert("Customer does not have enough money to purchase the item");
    // check why condition does not work with ===
  } else if (cash == price) {
    changeDueElement.innerHTML = 
      `<p>No change due - customer paid with exact cash</p>`;
  } else if (cashInDrawer < changeDue) {
    changeDueElement.innerHTML = 
      `<p>Status: INSUFFICIENT_FUNDS</p>`;
  } else if (cashInDrawer == changeDue) {
    changeDueElement.innerHTML = 
      `<p>Status: CLOSED</p>`;
      getChange(changeDue);
  } else {
    changeDueElement.innerHTML = 
      `<p>Status: OPEN</p>`;
    getChange(changeDue);
  }
});

Also, I would like to comment that the last test

When price is less than the value in the #cash element, total cash in drawer 
cid is equal to change due, and the #purchase-btn element is clicked, 
the value in the #change-due element should be "Status: CLOSED" with 
change due in coins and bills sorted in highest to lowest order.

at first I got it wrong, but next, whithout changing the code (just the cid array values) changed to “correct”.
I’m quite lost and would appreciate some insight.
Cheers

EDIT:
Funny, I just copied the code from the provided example (as an experiment) and it randomly fails at some tests… Now I’m completely lost :rofl:

example:
in you CID you have ONES = 1 and PENNY = 0.01.
your price is 19.50 and your cash is 20.
your change due is less than the current total in your CID but since you cannot give any other denomination to return the change due, you have to return insufficient funds.

1 Like

This for example gives incorrect answer, instead of INSUFFICIENT_FUNDS.

// cash 60
price = 41.35
cid = [ [ 'PENNY', 0.02 ],
  [ 'NICKEL', 0 ],
  [ 'DIME', 0.2 ],
  [ 'QUARTER', 1.5 ],
  [ 'ONE', 7 ],
  [ 'FIVE', 65 ],
  [ 'TEN', 40 ],
  [ 'TWENTY', 180 ],
  [ 'ONE HUNDRED', 200 ] ]
1 Like

You’re right! in that example I didn’t have enough pence for a complete change. Just needed to check if I could give all the money back. Thanks!
Still, I’m just testing, and adding a couple of comment lines triggers the last test to fail, so maybe when I polish the CSS it starts failing again :smiling_face_with_tear:
Can any admin check why this is happening? As far as know, those things shouldn’t make a test to fail…