Build a Cash Register Project

I’m having issues understanding why my code is not passing the test? I’ve checked the output into #change-due and the string is exactly the same as what the test is expecting. I suspect it’s either a bug or I’m missing some sort of formatting in the string (even though they’re exactly the same).

For example this test:

When price is 3.26 , the value in the #cash element is 100 , cid is [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]] , and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: OPEN TWENTY: $60 TEN: $20 FIVE: $15 ONE: $1 QUARTER: $0.5 DIME: $0.2 PENNY: $0.04" .

Is failing when the textContent of #change-due is correct based on this screenshot.

Any suggestions on what I’m missing here? Don’t worry about the script length, I plan on refactoring once I get it passing all tests.

HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Cash Register</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <p id="price"></p>
    <label for="cash">Cash: </label>
    <input id="cash" type="number" />
    <p id="change-due"></p>
    <button id="purchase-btn">Purchase</button>
	  <script src="script.js"></script>
  </body>
</html>

SCRIPT:

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 amountsToGiveBack = {
  onehundred: 0,
  twenty: 0,
  ten: 0,
  five: 0,
  one: 0,
  quarter: 0,
  dime: 0,
  nickel: 0,
  penny: 0
}

const priceText = document.getElementById('price');
const cashInput = document.getElementById('cash');
const changeDueText = document.getElementById('change-due');
const purchaseBtn = document.getElementById('purchase-btn');
const cidSorted = cid.reverse();

priceText.innerHTML = `<p>Price: $${price}</p>`;

purchaseBtn.addEventListener("click", () => {
  const cash = Number(cashInput.value).toFixed(2);
  const changeDue = Number((cash - price).toFixed(2));
  const totalCashInDrawer = calculateCashInDrawer();
  
  if (cash < price) {
    alert("Customer does not have enough money to purchase the item");
    return;
  }

  if (changeDue === 0) {
    changeDueText.innerText = "No change due - customer paid with exact cash";
    return;
  }

  if (changeDue > totalCashInDrawer) {
    changeDueText.innerText = "Status: INSUFFICIENT_FUNDS";
    return;
  }

  const drawerStatus = getDrawerStatus(changeDue, totalCashInDrawer);
  const changeDueStr = getChangeDueText(changeDue, totalCashInDrawer);

  changeDueText.innerText = `Status: ${drawerStatus} ${changeDueStr}`;
});

const calculateCashInDrawer = () => {
  let total = 0;
  cidSorted.forEach((currency) => {
    total += currency[1];
  });
  return Number(total.toFixed(2));
};

const getDrawerStatus = (changeDue, totalCashInDrawer) => {
  if (changeDue === totalCashInDrawer) {
    return "CLOSED";
  } else {
    return "OPEN";
  }
};

const getChangeDueText = (changeDue) => {
  let text = "";

  while (changeDue >= 100 && doesDrawerHaveEnough(100)) {
    changeDue = (changeDue - 100).toFixed(2);
    takeMoneyFromDrawer('onehundred', 100, 0);
  }

  while (changeDue >= 20 && doesDrawerHaveEnough(20)) {
    changeDue = (changeDue - 20).toFixed(2);
    takeMoneyFromDrawer('twenty', 20, 1);
  }

  while (changeDue >= 10 && doesDrawerHaveEnough(10)) {
    changeDue = (changeDue - 10).toFixed(2);
    takeMoneyFromDrawer('ten', 10, 2);
  }

  while (changeDue >= 5 && doesDrawerHaveEnough(5)) {
    changeDue = (changeDue - 5).toFixed(2);
    takeMoneyFromDrawer('five', 5, 3);
  }

  while (changeDue >= 1 && doesDrawerHaveEnough(1)) {
    changeDue = (changeDue - 1).toFixed(2);
    takeMoneyFromDrawer('one', 1, 4);
  }

  while (changeDue >= 0.25 && doesDrawerHaveEnough(0.25)) {
    changeDue = (changeDue - 0.25).toFixed(2);
    takeMoneyFromDrawer('quarter', 0.25, 5);
  }

  while (changeDue >= 0.1 && doesDrawerHaveEnough(0.1)) {
    changeDue = (changeDue - 0.1).toFixed(2);
    takeMoneyFromDrawer('dime', 0.1, 6);
  }

  while (changeDue >= 0.05 && doesDrawerHaveEnough(0.05)) {
    changeDue = (changeDue - 0.05).toFixed(2);
    takeMoneyFromDrawer('nickel', 0.05, 7);
  }

  while (changeDue >= 0.01 && doesDrawerHaveEnough(0.01)) {
    changeDue = (changeDue - 0.01).toFixed(2);
    takeMoneyFromDrawer('penny', 0.01, 8);
  }

  for (let i = 0; i < cidSorted.length; i++) {
    const currency = cidSorted[i][0].toLowerCase().split(" ").join("");
    if (amountsToGiveBack[currency] > 0) {
      text += `${cidSorted[i][0]}: $${calculateDollarAmount(currency, amountsToGiveBack[currency])} `;
    }
  }

  return text;
};


const doesDrawerHaveEnough = (amount) => {
  switch (amount) {
    case 100:
      return cidSorted[0][1] >= 100;
    case 20:
      return cidSorted[1][1] >= 20;
    case 10:
      return cidSorted[2][1] >= 10;
    case 5:
      return cidSorted[3][1] >= 5;
    case 1:
      return cidSorted[4][1] >= 1;
    case 0.25:
      return cidSorted[5][1] >= 0.25;
    case 0.1:
      return cidSorted[6][1] >= 0.10;
    case 0.05:
      return cidSorted[7][1] >= 0.05;
    case 0.01:
      return cidSorted[8][1] >= 0.01;
  }
}

const takeMoneyFromDrawer = (currency, amount, index) => {
  cidSorted[index][1] -= amount;
  amountsToGiveBack[currency] = (amountsToGiveBack[currency] + 1) || 1;
}

const calculateDollarAmount = (currency, amount) => {
  let total = 0;
  if (currency === 'onehundred') total = amount * 100;
  if (currency === 'twenty') total = amount * 20;
  if (currency === 'ten') total = amount * 10;
  if (currency === 'five') total = amount * 5;
  if (currency === 'one') total = amount * 1;
  if (currency === 'quarter') total = amount * 0.25;
  if (currency === 'dime') total = amount * 0.1;
  if (currency === 'nickel') total = amount * 0.05;
  if (currency === 'penny') total = amount * 0.01;
  return total;
};

I’ve just updated the output string to trim off that extra white space that’s being added and it’s still not passing.

Hi there!
Please start by moving this line of code to the specific function that needs it. If more than one function needs it, then it should be given as an argument to whomever needs it.

This is a step that may help your code pass because this variable is being initialized in the global scope and therefore will only get initialized once during the automated fcc testing. This may be messing up your algorithm.

No luck unfortunately. Tried moving the sorted cid variable outside of the global scope and passed it into the functions that needed it but it’s still not passing. Here’s my updated script.

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 amountsToGiveBack = {
  onehundred: 0,
  twenty: 0,
  ten: 0,
  five: 0,
  one: 0,
  quarter: 0,
  dime: 0,
  nickel: 0,
  penny: 0
}

const priceText = document.getElementById('price');
const cashInput = document.getElementById('cash');
const changeDueText = document.getElementById('change-due');
const purchaseBtn = document.getElementById('purchase-btn');

priceText.innerHTML = `<p>Price: $${price}</p>`;

purchaseBtn.addEventListener("click", () => {
  const cidSorted = cid.reverse();
  const cash = Number(cashInput.value).toFixed(2);
  const changeDue = Number((cash - price).toFixed(2));
  const totalCashInDrawer = calculateCashInDrawer(cidSorted);
  
  if (cash < price) {
    alert("Customer does not have enough money to purchase the item");
    return;
  }

  if (changeDue === 0) {
    changeDueText.innerText = "No change due - customer paid with exact cash";
    return;
  }

  if (changeDue > totalCashInDrawer) {
    changeDueText.innerText = "Status: INSUFFICIENT_FUNDS";
    return;
  }

  const drawerStatus = getDrawerStatus(changeDue, totalCashInDrawer);
  const changeDueStr = getChangeDueText(cidSorted, changeDue);

  changeDueText.innerText = `Status: ${drawerStatus} ${changeDueStr}`;
});

const calculateCashInDrawer = (cidSorted) => {
  let total = 0;
  cidSorted.forEach((currency) => {
    total += currency[1];
  });
  return Number(total.toFixed(2));
};

const getDrawerStatus = (changeDue, totalCashInDrawer) => {
  if (changeDue === totalCashInDrawer) {
    return "CLOSED";
  } else {
    return "OPEN";
  }
};

const getChangeDueText = (cidSorted, changeDue) => {
  let text = "";

  while (changeDue >= 100 && doesDrawerHaveEnough(cidSorted, 100)) {
    changeDue = (changeDue - 100).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'onehundred', 100, 0);
  }

  while (changeDue >= 20 && doesDrawerHaveEnough(cidSorted, 20)) {
    changeDue = (changeDue - 20).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'twenty', 20, 1);
  }

  while (changeDue >= 10 && doesDrawerHaveEnough(cidSorted, 10)) {
    changeDue = (changeDue - 10).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'ten', 10, 2);
  }

  while (changeDue >= 5 && doesDrawerHaveEnough(cidSorted, 5)) {
    changeDue = (changeDue - 5).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'five', 5, 3);
  }

  while (changeDue >= 1 && doesDrawerHaveEnough(cidSorted, 1)) {
    changeDue = (changeDue - 1).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'one', 1, 4);
  }

  while (changeDue >= 0.25 && doesDrawerHaveEnough(cidSorted, 0.25)) {
    changeDue = (changeDue - 0.25).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'quarter', 0.25, 5);
  }

  while (changeDue >= 0.1 && doesDrawerHaveEnough(cidSorted, 0.1)) {
    changeDue = (changeDue - 0.1).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'dime', 0.1, 6);
  }

  while (changeDue >= 0.05 && doesDrawerHaveEnough(cidSorted, 0.05)) {
    changeDue = (changeDue - 0.05).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'nickel', 0.05, 7);
  }

  while (changeDue >= 0.01 && doesDrawerHaveEnough(cidSorted, 0.01)) {
    changeDue = (changeDue - 0.01).toFixed(2);
    takeMoneyFromDrawer(cidSorted, 'penny', 0.01, 8);
  }

  for (let i = 0; i < cidSorted.length; i++) {
    const currency = cidSorted[i][0].toLowerCase().split(" ").join("");
    if (amountsToGiveBack[currency] > 0) {
      text += `${cidSorted[i][0]}: $${calculateDollarAmount(currency, amountsToGiveBack[currency])} `;
    }
  }

  return text;
};


const doesDrawerHaveEnough = (cidSorted, amount) => {
  switch (amount) {
    case 100:
      return cidSorted[0][1] >= 100;
    case 20:
      return cidSorted[1][1] >= 20;
    case 10:
      return cidSorted[2][1] >= 10;
    case 5:
      return cidSorted[3][1] >= 5;
    case 1:
      return cidSorted[4][1] >= 1;
    case 0.25:
      return cidSorted[5][1] >= 0.25;
    case 0.1:
      return cidSorted[6][1] >= 0.10;
    case 0.05:
      return cidSorted[7][1] >= 0.05;
    case 0.01:
      return cidSorted[8][1] >= 0.01;
  }
}

const takeMoneyFromDrawer = (cidSorted, currency, amount, index) => {
  cidSorted[index][1] -= amount;
  amountsToGiveBack[currency] = (amountsToGiveBack[currency] + 1) || 1;
}

const calculateDollarAmount = (currency, amount) => {
  let total = 0;
  if (currency === 'onehundred') total = amount * 100;
  if (currency === 'twenty') total = amount * 20;
  if (currency === 'ten') total = amount * 10;
  if (currency === 'five') total = amount * 5;
  if (currency === 'one') total = amount * 1;
  if (currency === 'quarter') total = amount * 0.25;
  if (currency === 'dime') total = amount * 0.1;
  if (currency === 'nickel') total = amount * 0.05;
  if (currency === 'penny') total = amount * 0.01;
  return total;
};

thanks for fixing that. That’s a good step forward.

The next thing you should look at is the result of some tests I did.

I set up the global price variable to be 19.5 and left the cid as you have it in your code right now but updated the quarters field to be $.4.75

Then I typed into the cash field 19.75, which should give me .25 back in change.
This worked as expected and the app showed:
Status: OPEN QUARTER: $0.25

Then, without reloading the app, I erased the 19.75 in the input field and typed in $100.
However, this time I was expecting the change to equal $80.5. But what happened was that change due was shown as:
Status: OPEN QUARTER: $0.75 ONE: $80

80.75? This suggests that something in the way you calculate the change is incorrect.

Please investigate by adding console.log statements and tracking what happens when you test in the way I did above.