Cash Register project failing last test, but output looks correct

Hi (first post!)

I’m having trouble with the final test on the Cash Register project. The output seems to meet all the requirements, so I’m at a loss as to what’s preventing it from passing. I’d really appreciate any help on this!

My code is here (Please pardon the stark html. I’ve been focusing on function over form :upside_down_face:)

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=0"/>
    <link rel="stylesheet" href="./styles.css"/>
    <title>Cash Register</title>
  </head>
  <body>
    <h1>Cash Register</h1>
    <strong>$</strong><input name="cash" id="cash" type="number"/>
    <button id="purchase-btn">Purchase</button>
    <div id="change-due"></div>
  <script src="./script.js"></script>
  </body>
  <footer>by rybernate</footer>
</html>

CSS

body {
  width: auto;
  margin: 0;
  align-content: center;
  text-align: center;
}

input {
  width: 10%;
  min-width: 50px;
  max-width: 100px;
}

footer{
  display: block;
  position: fixed;
  bottom: 0;
  width: 100%;
  height: 20px;
  align-content: center;
  text-align: center;
  color: #fff;
  background-color: #000;
  margin: 0;
  font-family: Trebuchet, sans-serif;
  font-size: .8rem;
}

JS

const purchaseBtn = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");
let cash = document.getElementById("cash");
let price = 19.5;

let cid = [
  ["PENNY", 0.5],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 0],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0]
];

let monValues = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100];

const cidLength = cid.length - 1;
const mvLength = monValues.length -1;
let regTotal = 0;
let change = 0;
let currency = 0;
let changeMsg = "";
let tally = [];

const getRegTotal = () => {
  for (let i=cidLength; i>=0; i--){
  regTotal = Number(cid[i][1] * 100) + regTotal;
  };
  regTotal = regTotal / 100;
  return;
};

const getNumberOfBillsAndCoins = () => {
  for (let i=mvLength; i>=0; i--){
     currency = Math.round((cid[i][1] * 100) / (monValues[i] * 100));
     tally.unshift(currency);
  };
  return;
};

const getChange = () => {
  let a = change*100;
  for (let i=mvLength; i>=0; i--){  
    const b = (monValues[i]*100);
    const c = (b * tally[i]);
    const d = Math.floor(a / b); 
    if (d !== 0 && d >= tally[i] && tally[i] != 0) { 
      a = Math.round(a - c);
      changeMsg += ` ` + cid[i][0] + `: $` + c / 100;
    } else if (d !== 0 && d < tally[i]) {
      a = Math.round(a - (d * b));
      changeMsg += ` ` + cid[i][0] + `: $` + (d * b) / 100; 
    } else {
      a = Math.round(a);
    };
    console.log(tally[i] + " " + b + " " + a + " " + c + " " + d + " " + regTotal);
  };
  if (a === 0 && change - regTotal !== 0) {
      changeDue.textContent = `Status: OPEN ${changeMsg}`;
      cash.value = "";
    } else if (a === 0 && change - regTotal === 0) {
      changeDue.textContent = `Status: CLOSED ${changeMsg}`;
      cash.value = "";
    } else {
      changeDue.textContent = `Status: INSUFFICIENT_FUNDS`;
      cash.value = "";
    };
  return;
};

const purchaseItem = () => {
  getNumberOfBillsAndCoins();
  getRegTotal();
  if (Number(cash.value) < price) {
    alert(`Customer does not have enough money to purchase the item`);
    cash.value = "";
  } else if (Number(cash.value) === price) {
    changeDue.textContent = `No change due - customer paid with exact cash`;
    cash.value = "";
  } else if (change > regTotal) {
    changeDue.textContent = `Status: INSUFFICIENT_FUNDS`;
    cash.value = "";
  } else {
    finalSale();
  };
  return;
};

const finalSale = () => {
  change = ((cash.value *100) - (price *100)) / 100;
  getChange();
  changeMsg = "";
  cash.value = "";
  regTotal = 0;
  currency = 0;
  tally = [];
  return;
};

purchaseBtn.addEventListener("click",purchaseItem);

The test that’s failing is

When price is 19.5 , the value in the #cash element is 20 , cid is [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]] , and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: CLOSED PENNY: $0.5" .

How are you confirming that your cash register is returning the correct status for the test?

Hi bbsmooth,

my console outputs:

tally[i] = the number of bills or coins in the register
b = the monetary value of 1 bill or coin in the register (x100 to eliminate decimals)
a = the amount of change due to the customer (x100 to eliminate decimals)
c = the total monetary value of each type of bill/coin in the register (x100 to eliminate decimals)
d = how many of each type of bill/coin is needed to produce the change
regTotal = the total value of the cash in the register

My getChange() function loops through each item in the cid array from $100 bills to pennies and takes what’s available from the register until the full amount of change is reached (change = 0). If there’s not enough change in the register it returns INSUFFICIENT_FUNDS, otherwise it appends the amount for each bill/coin to a status message that starts with “OPEN” if there’s still money left in the register after successfully providing the change due, or “CLOSED” if the change zeroed out the cash in the register.

Thanks for the pics, but I already saw all of that when I ran your code. What I don’t see is proof that your app is returning " Status: CLOSED PENNY: $0.5" for the given input. How would you go about proving that this is actually happening?

That’s in the first pic I added. The div with id change-due is being populated with the “Status: CLOSED PENNY: $0.5” in the html output.

(a === 0 && change - regTotal === 0) {
      changeDue.textContent = `Status: CLOSED ${changeMsg}`;

the scenario being tested meets this condition and the changeMsg that gets appended is " PENNY: $0.5"

I tried refactoring so that the status would be output by a variable, but same result :sob::

I’m suspicious of all the extra global variables you added

What extra variables? They’re all called in multiple functions, no?

I doubt that’s the issue, regardless. There’s really nothing different about the last test than any of the others except for the status saying “CLOSED” instead of “OPEN,” which you can see in my screenshot is running as expected. If it was an issue with variables, I’d think more than one of the tests would fail. All the others are passing except the last one. :man_shrugging:

All this should be avoided. Functions have return values so you don’t have to hide things in the global space. This is generally an antipattern because it’s really easy to do in a way that breaks your code.

The CID is changed between tests but your dirty values of these global variables aren’t changed by the tests.

Ok - I’ll try refactoring my functions next so that I don’t need to declare those variables globally. :crossed_fingers:

1 Like

@JeremyLT thank you so so much!! I should not have doubted you :sweat_smile: I was tired and cranky. I refactored my code as you suggested and all of the tests passed. The script is shorter & cleaner now, too.

Updated JS:

const purchaseBtn = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");
const cash = document.getElementById("cash");
let price = 19.5;

let cid = [
  ["PENNY", 0.5],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 0],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0]
];

const monValues = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100];
const cidLength = cid.length - 1;
const mvLength = monValues.length -1;

const getRegTotal = () => {
  let regTotal = 0;
  for (let i=cidLength; i>=0; i--){
    regTotal = Number(cid[i][1] * 100) + regTotal;
  };
  return regTotal = regTotal / 100;;
};

const getNumberOfBillsAndCoins = () => {
  const tally = [];
  for (let i=mvLength; i>=0; i--){
     tally.unshift(Math.round((cid[i][1] * 100) / (monValues[i] * 100)));
  };
  return tally;
};

const checkRegisterFunds = () => {
  const regTotal = getRegTotal();
  const change = ((cash.value *100) - (price *100)) / 100;
  if (Number(cash.value) < price) {
    alert("Customer does not have enough money to purchase the item");
  } else if (Number(cash.value) === price) {
    changeDue.textContent = "No change due - customer paid with exact cash";
  } else if (change > regTotal) {
    changeDue.textContent = "Status: INSUFFICIENT_FUNDS";
  } else {
    getChange(regTotal, change);
  };
  return cash.value = "";
};

const getChange = (regTotal, change) => {
  const tally = getNumberOfBillsAndCoins();
  let a = change*100;
  let changeMsg = "";
  for (let i=mvLength; i>=0; i--){  
    const b = (monValues[i]*100);
    const c = (b * tally[i]);
    const d = Math.floor(a / b); 
    if (d !== 0 && d >= tally[i] && tally[i] != 0) { 
      a = Math.round(a - c);
      changeMsg += " " + cid[i][0] + ": $" + c / 100;
    } else if (d !== 0 && d < tally[i]) {
      a = Math.round(a - (d * b));
      changeMsg += " " + cid[i][0] + ": $" + (d * b) / 100; 
    } else {
      a = Math.round(a);
    };
  };
  if (a === 0 && regTotal - change !== 0) {
      changeDue.textContent = "Status: OPEN" + changeMsg;
  } else if (a === 0 && regTotal - change === 0) {
      changeDue.textContent = "Status: CLOSED" + changeMsg;
  } else {
      changeDue.textContent = "Status: INSUFFICIENT_FUNDS";
  };
  return cash.value = "";
};

purchaseBtn.addEventListener("click",checkRegisterFunds);
cash.addEventListener("keydown", e => {
  if (e.key === "Enter") {
    checkRegisterFunds();
  }
});

I learned A LOT from this project. Thanks again for your help!!

1 Like