Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

Build a Cash Register Project - Build a Cash Register

Hello, the three files have been update. The test runs fine (or so I think). This is the remaining bug. It looks related to floating point but I haven’t found a way to break it with Math.round added.

  1. 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.

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="stylesheet" href="styles.css">
    <title>Document</title>
</head>
<body>
    <main>
        <input id="cash">
        <div id="change-due"></div>
        <button id="purchase-btn">pay</button>
        <div id="change-due2">
            <p id="cidRemainder"></p>
        </div>
    </main>
</body>
<script src="script.js"></script>
</html>
/* file: script.js */
const cartRef_proto = {
  PENNY: 0.01,
  NICKEL: 0.05,
  DIME: 0.1,
  QUARTER: 0.25,
  ONE: 1.0,
  FIVE: 5.0,
  TEN: 10.0,
  TWENTY: 20.0,
  "ONE HUNDRED": 100.0,
};

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],
];

// -----------------DOOM---------------------
const inputElement = document.getElementById("cash");
const changeElement = document.getElementById("change-due");
const purchaseBtn = document.getElementById("purchase-btn");
const cidRemainder = document.getElementById("cidRemainder");
let price = 20;
let payment = 0;

  // -------------PAY-------------
const pay = () => {
  const cidObj = Object.fromEntries(cid);
  let cidTotal = Math.round((Object.values(cidObj).reduce((acc, el) => acc + el, 0))*100)/100
  payment = Math.round(inputElement.value*100)/100;
  const change = Math.round((payment - price) * 100) / 100;
  // const change = parseFloat(payment - price).toFixed(2);
  const msg1 = "Customer does not have enough money to purchase the item";
  const msg2 = "No change due - customer paid with exact cash";
  const msg3 = "Status: INSUFFICIENT_FUNDS";

  // -------------CHECK-------------
  if (payment < price) {
    changeElement.textContent = msg1;
    alert(msg1);
    return;
  } else if (price === payment) {
    changeElement.textContent = msg2;
    return;
  } else if (cidTotal < change) {
    changeElement.textContent = msg3;
    return;
  } else {
    calChange(payment);
  }
};

// Convert cartRef to [[][]], reverse
// Convert cid array to object
// Conver it back for updating global
const calChange = (payment) => {
  printcid();
  const cartRef = Object.entries(cartRef_proto).reverse();
  const cidObj = Object.fromEntries(cid);
  let memValue = [];
  let memName = [];
  let burntValue = 0;
  // let change = parseFloat((payment - price).toFixed(2));
  let change = Math.round((payment - price) * 100) / 100;
  let cidTotal = Object.values(cidObj).reduce((acc, el) => acc + el, 0);

  //[i[0 1]i[0 1]]
  for (let i of cartRef) {
    let valueRef = i[1];
    let nameRef = i[0];

    while (change >= valueRef && cidObj[nameRef] >= valueRef) {
      // burntValue = parseFloat((burntValue + valueRef).toFixed(2));
      // change = parseFloat((change - valueRef).toFixed(2));
      // cidObj[nameRef] = parseFloat((cidObj[nameRef] - valueRef).toFixed(2));
      // cidTotal = parseFloat((cidTotal - valueRef).toFixed(2));
      burntValue = Math.round((burntValue + valueRef) * 100) / 100;
      change = Math.round((change - valueRef) * 100) / 100;
      cidObj[nameRef] = Math.round((cidObj[nameRef] - valueRef) * 100) / 100;
      cidTotal = Math.round((cidTotal - valueRef) * 100) / 100; 
    }

    if (burntValue > 0) {
      memValue.push(burntValue);
      memName.push(nameRef);
      burntValue = 0;
    }
  }

  // -------------POST-CHANGE-------------
  //Globel cid update, convent back [[][]]
  cid = Object.entries(cidObj);
  printcid();
  console.log(change)
  console.log(cidTotal)

    // -------------CLOSE-------------
  if (change === cidTotal && change === 0 && cidTotal === 0) {
    changeElement.textContent = `Status: CLOSED ${memName
      .map((name, index) => `${name}: $${memValue[index]}`)
      .join(" ")}`;
    purchaseBtn.disabled = true;
    printcid();
    return;
  }

  if (change > 0) {
    alert("Status: INSUFFICIENT_FUNDS");
    changeElement.textContent = "Status: INSUFFICIENT_FUNDS";
    printcid();
    return;
  }

  // -------------PRINT-------------
  function printcid(){
      const printcid=cid.map(([v, a])=>`${v}, ${a}`).join("<br>")
      cidRemainder.innerHTML=`Total in Drawer: ${cidTotal}<br><br>${printcid}`}

  updateRender(memName, memValue);
  console.log(cidTotal);
  console.log(cid);
};

const updateRender = (memName, memValue) => {
  // changeElement.textContent = "";
  changeElement.textContent = `Status: OPEN `;
  for (let i = 0; i < memValue.length; i++) {
    changeElement.textContent += `${memName[i]}: $${memValue[i]} `;
  }
};

// -----------------EVENTS---------------------
purchaseBtn.addEventListener("click", pay);
/* file: styles.css */
  * {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
:root {
  --cool: rgb(209, 212, 211);
  --text: #37392e;
  --body: #eee5e5;
  --input: #ddcecd;
  --ascent: #28afb0;
  --ascent2: #19647e;
}
body {
  background-color: var(--ascent2);
   font-family: Arial, sans-serif;
  color: var(--text);
}
main {
  width: 300px;
  margin: 20px auto;
  padding:20px;
  display: block;
  text-align: center;
  background-color: var(--body);
  border-radius:5px
}

#change-due, #change-due2 {
  margin: 10px auto;
  padding: 20px;
  width: 100%;
  min-width: 200px;
  min-height: 50px;
  border: 1px solid black;
  background-color: var(--cool);
 display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  border-radius: 5px;

}

input { 
  width: 100%;
  max-width: 200px;
  border: 1px solid black;
  margin: 10px 0;
  padding: 8px;
  background-color: var(--input);
  border-radius: 5px;
}

button{
  display:block;
  margin: 10px auto;
  width: 100px;
  padding: 10px;
  background-color:var(--ascent);
  color:white;
  border:none;
  border-radius:5px;
}
button:hover{
  background-color:var(--ascent2);
}

#cidRemainder, p{
max-width:300px;
width:100%;
height:auto;
padding: 10px;
align-items: center;
word-wrap: break-word;
border-radius: 5px;
background-color:aqua;
}

Your browser information:

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

Challenge Information:

Build a Cash Register Project - Build a Cash Register

All of these global variables prevent your code from running twice in a row, but the tests run back to back

Thank you~ I’ll try encapsulating them (apart from cid and price) on rewrite. Do you know if updating the original cid values is a requirement?

The instructions don’t say to change the cid, so I assume that is not a requirement.

1 Like

Files and post updated above.

Note - it’s better to make a new post so we don’t lose history of the conversation

Better if you repost your new code in a new post in this thread.

If you’ve changed the code in the original post this thread will be impossible for anyone else to follow and make no sense.

Noted.

—Reposting for reference—
This is the remaining bug. It looks related to floating point but I haven’t found a way to break it with Math.round added.

Going to test breaking and converting to cents on a helper function.

  1. 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.

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="stylesheet" href="styles.css">
    <title>Document</title>
</head>
<body>
    <main>
        <input id="cash">
        <div id="change-due"></div>
        <button id="purchase-btn">pay</button>
        <div id="change-due2">
            <p id="cidRemainder"></p>
        </div>
    </main>
</body>
<script src="script.js"></script>
</html>
/* file: script.js */
const cartRef_proto = {
  PENNY: 0.01,
  NICKEL: 0.05,
  DIME: 0.1,
  QUARTER: 0.25,
  ONE: 1.0,
  FIVE: 5.0,
  TEN: 10.0,
  TWENTY: 20.0,
  "ONE HUNDRED": 100.0,
};

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],
];

// -----------------DOOM---------------------
const inputElement = document.getElementById("cash");
const changeElement = document.getElementById("change-due");
const purchaseBtn = document.getElementById("purchase-btn");
const cidRemainder = document.getElementById("cidRemainder");
let price = 20;
let payment = 0;

  // -------------PAY-------------
const pay = () => {
  const cidObj = Object.fromEntries(cid);
  let cidTotal = Math.round((Object.values(cidObj).reduce((acc, el) => acc + el, 0))*100)/100
  payment = Math.round(inputElement.value*100)/100;
  const change = Math.round((payment - price) * 100) / 100;
  // const change = parseFloat(payment - price).toFixed(2);
  const msg1 = "Customer does not have enough money to purchase the item";
  const msg2 = "No change due - customer paid with exact cash";
  const msg3 = "Status: INSUFFICIENT_FUNDS";

  // -------------CHECK-------------
  if (payment < price) {
    changeElement.textContent = msg1;
    alert(msg1);
    return;
  } else if (price === payment) {
    changeElement.textContent = msg2;
    return;
  } else if (cidTotal < change) {
    changeElement.textContent = msg3;
    return;
  } else {
    calChange(payment);
  }
};

// Convert cartRef to [[][]], reverse
// Convert cid array to object
// Conver it back for updating global
const calChange = (payment) => {
  printcid();
  const cartRef = Object.entries(cartRef_proto).reverse();
  const cidObj = Object.fromEntries(cid);
  let memValue = [];
  let memName = [];
  let burntValue = 0;
  // let change = parseFloat((payment - price).toFixed(2));
  let change = Math.round((payment - price) * 100) / 100;
  let cidTotal = Object.values(cidObj).reduce((acc, el) => acc + el, 0);

  //[i[0 1]i[0 1]]
  for (let i of cartRef) {
    let valueRef = i[1];
    let nameRef = i[0];

    while (change >= valueRef && cidObj[nameRef] >= valueRef) {
      // burntValue = parseFloat((burntValue + valueRef).toFixed(2));
      // change = parseFloat((change - valueRef).toFixed(2));
      // cidObj[nameRef] = parseFloat((cidObj[nameRef] - valueRef).toFixed(2));
      // cidTotal = parseFloat((cidTotal - valueRef).toFixed(2));
      burntValue = Math.round((burntValue + valueRef) * 100) / 100;
      change = Math.round((change - valueRef) * 100) / 100;
      cidObj[nameRef] = Math.round((cidObj[nameRef] - valueRef) * 100) / 100;
      cidTotal = Math.round((cidTotal - valueRef) * 100) / 100; 
    }

    if (burntValue > 0) {
      memValue.push(burntValue);
      memName.push(nameRef);
      burntValue = 0;
    }
  }

  // -------------POST-CHANGE-------------
  //Globel cid update, convent back [[][]]
  cid = Object.entries(cidObj);
  printcid();
  console.log(change)
  console.log(cidTotal)

    // -------------CLOSE-------------
  if (change === cidTotal && change === 0 && cidTotal === 0) {
    changeElement.textContent = `Status: CLOSED ${memName
      .map((name, index) => `${name}: $${memValue[index]}`)
      .join(" ")}`;
    purchaseBtn.disabled = true;
    printcid();
    return;
  }

  if (change > 0) {
    alert("Status: INSUFFICIENT_FUNDS");
    changeElement.textContent = "Status: INSUFFICIENT_FUNDS";
    printcid();
    return;
  }

  // -------------PRINT-------------
  function printcid(){
      const printcid=cid.map(([v, a])=>`${v}, ${a}`).join("<br>")
      cidRemainder.innerHTML=`Total in Drawer: ${cidTotal}<br><br>${printcid}`}

  updateRender(memName, memValue);
  console.log(cidTotal);
  console.log(cid);
};

const updateRender = (memName, memValue) => {
  // changeElement.textContent = "";
  changeElement.textContent = `Status: OPEN `;
  for (let i = 0; i < memValue.length; i++) {
    changeElement.textContent += `${memName[i]}: $${memValue[i]} `;
  }
};

// -----------------EVENTS---------------------
purchaseBtn.addEventListener("click", pay);
/* file: styles.css */
  * {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
:root {
  --cool: rgb(209, 212, 211);
  --text: #37392e;
  --body: #eee5e5;
  --input: #ddcecd;
  --ascent: #28afb0;
  --ascent2: #19647e;
}
body {
  background-color: var(--ascent2);
   font-family: Arial, sans-serif;
  color: var(--text);
}
main {
  width: 300px;
  margin: 20px auto;
  padding:20px;
  display: block;
  text-align: center;
  background-color: var(--body);
  border-radius:5px
}

#change-due, #change-due2 {
  margin: 10px auto;
  padding: 20px;
  width: 100%;
  min-width: 200px;
  min-height: 50px;
  border: 1px solid black;
  background-color: var(--cool);
 display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  border-radius: 5px;

}

input { 
  width: 100%;
  max-width: 200px;
  border: 1px solid black;
  margin: 10px 0;
  padding: 8px;
  background-color: var(--input);
  border-radius: 5px;
}

button{
  display:block;
  margin: 10px auto;
  width: 100px;
  padding: 10px;
  background-color:var(--ascent);
  color:white;
  border:none;
  border-radius:5px;
}
button:hover{
  background-color:var(--ascent2);
}

#cidRemainder, p{
max-width:300px;
width:100%;
height:auto;
padding: 10px;
align-items: center;
word-wrap: break-word;
border-radius: 5px;
background-color:aqua;
}

Update:
Broke code into smaller functions, referencing values *100.
Reverted values if insufficient funds.
Error 19 remains.

const cartRef_proto = {
  PENNY: 0.01,
  NICKEL: 0.05,
  DIME: 0.1,
  QUARTER: 0.25,
  ONE: 1.0,
  FIVE: 5.0,
  TEN: 10.0,
  TWENTY: 20.0,
  "ONE HUNDRED": 100.0,
};

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]
];

// -----------------DOOM---------------------
const inputElement = document.getElementById("cash");
const changeElement = document.getElementById("change-due");
const purchaseBtn = document.getElementById("purchase-btn");
const cidRemainder = document.getElementById("cidRemainder");
let price = 10;


  // -------------UTILITY-------------
  const getcidCents = (x) => {
    return x.map(([currency,value])=>[currency, Math.round(value*100)])
  }
  const getcidTotal = (cidValues) =>{
    return Math.round((cidValues).reduce((acc, el) => acc + el, 0))
    }

  // -------------PAY-------------
const pay = () => {
  // console.log(cidCents)
  const cidCents = getcidCents(cid);
  const cidObj = Object.fromEntries(cidCents);
  const cidValues = Object.values(cidObj)
  const cidTotal = getcidTotal(cidValues)
  const priceCents = price*100
  const payment = (inputElement.value)*100;
  const change = payment - priceCents;
  // console.log(cidTotal)
  const msg1 = "Customer does not have enough money to purchase the item";
  const msg2 = "No change due - customer paid with exact cash";
  const msg3 = "Status: INSUFFICIENT_FUNDS";
  // console.log(cidCents)

  // -------------CHECK-------------
  if (payment < priceCents) {
    changeElement.textContent = msg1;
    alert(msg1);
    return;
  } else if (priceCents === payment) {
    changeElement.textContent = msg2;
    return;
  } else if (cidTotal < change) {
    changeElement.textContent = msg3;
    return;
  } else{
    calChange(cidTotal, change, cidObj);
  }
};

// Convert cartRef to [[][]], reverse
// Convert cid array to object and back for updating global
const calChange = (cidTotal, change, cidObj) => {
  const cartRef1 = Object.entries(cartRef_proto).reverse();
  const cartRef = getcidCents(cartRef1);
  const cidObjRevert = {...cidObj};
  const cidTotalRevert = cidTotal/100;
  // console.log(cartRef)
  let memValue = [];
  let memName = [];
  let burntValue = 0;

  //[i[0 1]i[0 1]]
  for (let i of cartRef) {
    let valueRef = i[1];
    let nameRef = i[0];

    while (change >= valueRef && cidObj[nameRef] >= valueRef) {
      burntValue = burntValue + valueRef;
      change = change - valueRef;
      cidObj[nameRef] =cidObj[nameRef] - valueRef
      cidTotal = cidTotal - valueRef 
    }
    if (burntValue > 0) {
      memValue.push(burntValue);
      memName.push(nameRef);
      burntValue = 0;
    }
  }

  // -------------POST-CHANGE-------------
  //Globel cid update, convent back [[][]]
  const cidObj_updated = Object.entries(cidObj).map(([k,v])=>[k,v/100])
  cid = cidObj_updated
  const cidTotal_updated = cidTotal/100

  console.log(change)

    // -------------CLOSE-------------
  if (change === cidTotal && change === 0 && cidTotal === 0) {
    changeElement.textContent = `Status: CLOSED ${memName
      .map((name, index) => `${name}: $${(memValue[index]/100)}`)
      .join(" ")}`;
    purchaseBtn.disabled = true;
    printcid(cidTotal_updated);
    return;
  }

  if (change > 0) {
    cidObj = cidObjRevert
    const cidObj_updated = Object.entries(cidObjRevert).map(([k,v])=>[k,v/100])
    cid = cidObj_updated
    alert("Status: INSUFFICIENT_FUNDS");
    changeElement.textContent = "Status: INSUFFICIENT_FUNDS";
    printcid(cidTotalRevert);
    return;
  }

  // -------------PRINT-------------
  printcid(cidTotal_updated);
  updateRender(memName, memValue);

  function printcid(cidTotal){
      console.log(cidTotal)
      const printCid = cid.map(([v, a])=>`${v}, ${a}`).join("<br>")
      cidRemainder.innerHTML=`Total in Drawer: ${cidTotal}<br><br>${printCid}`
  }
};

const updateRender = (memName, memValue) => {
  changeElement.textContent = `Status: OPEN `;
  for (let i = 0; i < memValue.length; i++) {
    changeElement.textContent += `${memName[i]}: $${(memValue[i]/100)} `;
  }
};

// -----------------EVENTS---------------------
purchaseBtn.addEventListener("click", pay);

Update:
I rewrote the code in it’s entirety, splitting up several smaller functions.

The previous being rejected was probably a floating error or lack of proper encapsulation(?)

Units were converted with *100 (Instead of parseInt.toFixed(2)) before any comparisons with most in the core function. Local units references the converted values. Of note, Math.round after *100.

This is, in my experience, the easiest way to avoid floating point issues - use cents instead

1 Like