Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

Struggling with test cases 12 and 11:
11. When price is 19.5, the value in the #cash element is 20, 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 QUARTER: $0.5”.
Waiting: 12. 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”.

My goal was to loop through the 2D array cid backwards looking at the big bills first, deconstruct inner arrays into variables for amount and unit/denomination. Check if money of that specific denomination is available in drawer and that there is still change to be given back. And only then subtract that amount from cash in drawer. Create an array to keep track of the amount to be given back and in what units, convert that array into a string and output it with the status.

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">
    <link rel="stylesheets" href="styles.css">
    <title>Cash Register</title>
  </head>
  <body>
    <div class="container">
      <h1>Cash Register</h1>
      <form>
        <label for="cash"></label>
        <input id="cash" name="cash" type="number">
        <button type="submit" id="purchase-btn">Buy</button>
      </form>
      <div id="change-due">Change Due: </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>
/* file: script.js */
let price = 19.5; //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 cashInput = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");

 const calculateChange = (cashGiven, price) => {
    let change = (Number(cashGiven) * 100 - price * 100) / 100;
    //console.log(`Price in dollars: ${price}`);
    //console.log(`Price in cents: ${100*price}`);
    //console.log(`Cash Given in dollars: ${cashGiven}`);
    console.log(`Cash Given in cents: ${100*cashGiven}`);
    console.log(`Change: ${change}`);
    //"Status: OPEN TWENTY: $60 TEN: $20 FIVE: $15 ONE: $1 QUARTER: $0.5 DIME: $0.2 PENNY: $0.04"
    return change;
}

//console.log(`Change due (cents): ${change}`);
//console.log(`Cash in drawer total (cents): ${cidTotal}`);
//console.log(`cidTotal < change? ${cidTotal < change}`);

//console.log(`cidTotal: ${cidTotal}`)
purchaseBtn.addEventListener("click", (event) => {
  event.preventDefault();

  const cashInputVal = Number(cashInput.value);
  let status = "";
  let change = 0;
  let changeArr = [];
  
  // cash in drawer as cents = 33541 or $335.41
  const cidTotal = cid.reduce((acc, el)=> acc + Math.round(el[1] * 100), 0) / 100;

  if (cashInputVal < price) {
    alert("Customer does not have enough money to purchase the item");
    return;
  }
  if (cashInputVal === price) {
    changeDue.innerText = "No change due - customer paid with exact cash";
    return;
  }
  
  change = calculateChange(cashInputVal, price);

  if (cashInputVal > price) {
    if(cidTotal < change){
      status = "INSUFFICIENT_FUNDS";
      changeDue.innerText =`Status: ${status}`;
    }
    else if(cidTotal === change){
      status = "CLOSED";
      changeDue.innerText =`Status: ${status}`;
    }
    //if(cidTotal > change)
     else{
      status = "OPEN";
      // IRL I would start with the largest bills and remove them from the register by subtracting, 
      // like if I had $17.34 I would see how many tens I need, then how many fives, then ones, then quarters and dimes etc.
      // and subtracting my change from each unit/denomination and updating the array
      

      const unitValues = {
        "PENNY": 0.01,
        "NICKEL": 0.05,
        "DIME": 0.10,
        "QUARTER": 0.25,
        "ONE": 1.00,
        "FIVE": 5.00,
        "TEN": 10.00,
        "TWENTY": 20.00,
        "ONE HUNDRED": 100.00
      };

      
      // loop backwards thru the 2d array cid array big numbers/bills are first
      for (let i = cid.length - 1; i >= 0; i--){
        // destructure inner array to break it up into units/denominations and cash
        let [unit, amount] = cid[i];
        let unitValue = unitValues[unit];
        let amountToGive = 0;

        // while money of that denomination is available in draw
        // and still change to be given back
        while (amount >= unitValue && unitValue <= change) {
          //update change
          change = parseFloat((change - unitValue).toFixed(2));
          //update amount of cash in drawer
          amount = parseFloat((amount - unitValue).toFixed(2));
          //update amount to give
          amountToGive = parseFloat((amountToGive + unitValue).toFixed(2));
        }
        //populate the change array
        if (amountToGive > 0) {
          changeArray.push([unit, amountToGive]);
        }
      }
      const formattedChangeStr = changeArray.map(([unit, amount]) => `${unit}: $${amount.toFixed(2)}`).join(' ')
      changeDue.innerText = `Status: ${status} ${formattedChangeStr}`;
    }
  }
})
/* file: styles.css */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0
}
html, body {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #fff;
}
.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: start;
  background-color: rgb(124, 228, 124);
  width: 25rem;
  height: 25rem;
  border-radius: 10px;
  margin-top: 40px;
}

h1 {
  margin-top: 40px;
  margin-bottom: 20px;
}

form{
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
}

input {
  height: 20px;
}

#purchase-btn {
  width: 40px;
  height: 20px;
  font-size: 15px;
}

#change-due {
  margin-top: 20px;
  display: flex;
  align-items: center;
}

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15

Challenge Information:

Build a Cash Register Project - Build a Cash Register

What happens if you try to test those cases manually by setting cid and price?

1 Like

Please do not open duplicate topics. Just open one topic per lab.

Sorry about that, my mistake.

It’ says reference error cannot find changedArray. I initialized it as changeArr! Now all of my tests are passing except for the last 4. If I had to guess I think it’s because currently all my logic for creating the output string is only in the else case. I think I will need to create a function and call that every time I update changeDue.innerText

1 Like

Actually, that didn’t work either.

I’m still struggling with test case 18: 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" .

When I manually input the values for price cid and cash I get “INSUFFICENT_FUNDS” instead of “CLOSED”.

Updated Code:

let price = 19.5; //1,87
let cid = [
  ['PENNY', 0.01], //1.01
  ['NICKEL', 0],
  ['DIME', 0],
  ['QUARTER', 0],
  ['ONE',1],
  ['FIVE', 0],
  ['TEN', 0],
  ['TWENTY', 0],
  ['ONE HUNDRED', 0]
];

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

 const calculateChange = (cashGiven, price) => {
    let change = (Number(cashGiven) * 100 - price * 100) / 100;
    //console.log(`Price in dollars: ${price}`);
    //console.log(`Price in cents: ${100*price}`);
    //console.log(`Cash Given in dollars: ${cashGiven}`);
    console.log(`Cash Given in cents: ${100*cashGiven}`);
    console.log(`Change: ${change}`);
    //"Status: OPEN TWENTY: $60 TEN: $20 FIVE: $15 ONE: $1 QUARTER: $0.5 DIME: $0.2 PENNY: $0.04"
    return change;
}

//console.log(`Change due (cents): ${change}`);
//console.log(`Cash in drawer total (cents): ${cidTotal}`);
//console.log(`cidTotal < change? ${cidTotal < change}`);

//console.log(`cidTotal: ${cidTotal}`)
purchaseBtn.addEventListener("click", (event) => {
  event.preventDefault();

  const cashInputVal = Number(cashInput.value);
  let status = "";
  let change = 0;
  let changeArray = [];
  
  // cash in drawer as cents = 33541 or $335.41
  const cidTotal = cid.reduce((acc, el)=> acc + Math.round(el[1] * 100), 0) / 100;

  if (cashInputVal < price) {
    alert("Customer does not have enough money to purchase the item");
    return;
  }
  if (cashInputVal === price) {
    changeDue.innerText = "No change due - customer paid with exact cash";
    return;
  }
  
  change = calculateChange(cashInputVal, price);

  if (cashInputVal > price) {
    if(cidTotal < change){
      status = "INSUFFICIENT_FUNDS";
      changeDue.innerText =`Status: ${status}`;
    }
    else if(cidTotal === change){
      status = "CLOSED";
      changeDue.innerText =`Status: ${status}`;
    }
    //if(cidTotal > change)
     else{
      status = "OPEN";
   

      const unitValues = {
        "PENNY": 0.01,
        "NICKEL": 0.05,
        "DIME": 0.10,
        "QUARTER": 0.25,
        "ONE": 1.00,
        "FIVE": 5.00,
        "TEN": 10.00,
        "TWENTY": 20.00,
        "ONE HUNDRED": 100.00
      };

      
      // loop backwards thru the 2d array cid array big numbers/bills are first
      for (let i = cid.length - 1; i >= 0; i--){
        // destructure inner array to break it up into units/denominations and cash
        let [unit, amount] = cid[i];
        let unitValue = unitValues[unit];
        let amountToGive = 0;

        // while money of that denomination is available in draw
        // and still change to be givrn back
        while (amount >= unitValue && unitValue <= change) {
          //update change
          change = parseFloat((change - unitValue).toFixed(2));
          //update emount of cash in drawer
          amount = parseFloat((amount - unitValue).toFixed(2));
          //update amount to give
          amountToGive = parseFloat((amountToGive + unitValue).toFixed(2));
        }
        //populate the change array
        if (amountToGive > 0) {
          changeArray.push([unit, amountToGive]);
        }

      }
      if (change > 0) {
        // couldn't give back full change
        status = "INSUFFICIENT_FUNDS";
        changeDue.innerText = `Status: ${status}`;
        return;
      }

      if (cidTotal === calculateChange(cashInputVal, price)) {
        status = "CLOSED";
        changeArray = [...cid];
      }
      else {
        status = "OPEN";
      }
      const formattedChangeStr = changeArray.map(([unit, amount]) => `${unit}: $${amount.toFixed(2)}`).join(' ')
      changeDue.innerText = `Status: ${status} ${formattedChangeStr}`;
    }
  }
})

I’ve edited your post to improve the readability of the code. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (').

1 Like

what is the value of change here in that case?

change is 0.49 when I log it into the console

Ok, so why did the while loop stop short?

I dont think so. I added a comment in the while loop and it still prints that comment:

 // while money of that denomination is available in draw
        // and still change to be givrn back
        while (amount >= unitValue && unitValue <= change) {
          //update change
          change = parseFloat((change - unitValue).toFixed(2));
          //update emount of cash in drawer
          amount = parseFloat((amount - unitValue).toFixed(2));
          //update amount to give
          amountToGive = parseFloat((amountToGive + unitValue).toFixed(2));
          console.log('end of while loop?');
        }
        //populate the change array
        if (amountToGive > 0) {
          changeArray.push([unit, amountToGive]);
        }

      }

How many times does it print that comment? How many pennies do you have in the register? How many times should that comment be printed? One iteration should not be enough.

in this test case there is only 1 penny in the register. It only prints one time. I think it should print 9 times or the length of the cid array.

let cid = [
  ['PENNY', 0.01], //1.01
  ['NICKEL', 0],
  ['DIME', 0],
  ['QUARTER', 0],
  ['ONE',1],
  ['FIVE', 0],
  ['TEN', 0],
  ['TWENTY', 0],
  ['ONE HUNDRED', 0]
];

How many pennies does this test case say there are?

My bad I changed my cid and didn’t put it back to the inputs for this test case. It should be 50 pennies for test case 18.

Ok, so back to here. What happens at this point. this is what triggers the status

it outputs 0.49

Even when you fix the number of pennies?

If so, that goes back to my questions above - how many times should that loop actually execute?

now, it says “CLOSED” but it doesn’t include the “PENNIES:$ 0.5”