Build a Cash Register Project

I ran the tests manually by myself and they seem to yield the correct/expected output according to the test criteria, however when running the test through the checker, several tests fail, specifically, tests 12, 13, 14, 15, and 19. I have tried several workarounds but none seemed to work. Any help would be greatly appreciated, thanks!

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>cashRegister</title>
    <link rel="stylesheet" href="./styles.css" />
  </head>
  <body>
    <main id="grid-wrapper">
      <div id="title-container" class="container">
        <h1 id="title">Cash Register by @PeppermintSnow</div>
      </div>
      <div id="item-container" class="container">
        <h2 id="item-title">Item Information</h2>
        <div class="content-container">
          <table id="item-info-container">
            <tr>
              <th>Item ID</th>
              <th>Quantity</th>
              <th>Price</th>
              <th>Total</th>
            </tr>
            <tr id="item-info">
              <td>#000000</td>
              <td>0</td>
              <td>$0.00</td>
              <td>$0.00</td>
            </tr>
          </table>
        </div>
      </div>
      <div id="cash-container" class="container">
        <h2 id="cash-title">Payment</h2>
        <div class="content-container">
          <p id="price">Price to be paid: $0.00</p>
          <input id="cash" type="number" placeholder="0.00" />
          <div id="numpad">
            <button id="numpad9" class="numkey">9</button>
            <button id="numpad8" class="numkey">8</button>
            <button id="numpad7" class="numkey">7</button>
            <button id="numpad6" class="numkey">6</button>
            <button id="numpad5" class="numkey">5</button>
            <button id="numpad4" class="numkey">4</button>
            <button id="numpad3" class="numkey">3</button>
            <button id="numpad2" class="numkey">2</button>
            <button id="numpad1" class="numkey">1</button>
            <button id="numpad0" class="numkey">0</button>
            <button id="numpad-dot" class="numkey2">.</button>
            <button id="clear-all-btn" class="numkey2">AC</button>
            <button id="backspace-btn" class="numkey2">C</button>
            <button id="purchase-btn">Purchase</button>
          </div>
        </div>
      </div> 
      <div id="change-container" class="container">
        <h2 id="change-title">Change</h2>
        <div class="content-container">
          <div id="change-due"></div>
        </div>
      </div>
      <div id="cid-container" class="container">
        <h2 id="cid-title">Cash In Drawer</h2>
        <div class="content-container">
          <table id="cid">
            <tr>
              <td>Penny</td>
              <td id="cid-penny" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>Nickel</td>
              <td id="cid-nickel" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>Dime</td>
              <td id="cid-dime" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>Quarter</td>
              <td id="cid-quarter" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>One</td>
              <td id="cid-one" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>Five</td>
              <td id="cid-five" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>Ten</td>
              <td id="cid-ten" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>Twenty</td>
              <td id="cid-ten" class="cid">$0.00</td>
            </tr>
            <tr>
              <td>Hundred</td>
              <td id="cid-ten" class="cid">$0.00</td>
            </tr>
          </table>
        </div>
      </div>
      <div id="history-container" class="container">
        <h2 id="history-title">Purchase History</h2>
        <div class="content-container">
          <table id="history">
            <tr>
              <th>Item ID</th>
              <th>Quantity</th>
              <th>Cash</th>
              <th>Change</th>
            </tr>
          </table>
        </div>
      </div>
    </main>
    <script src="./script.js"></script>
  </body>
</html>

CSS

:root {
  --bg: #686D76;
  --container-bg: #eeeeee;
  --border: #373A40;
  --accent1: #7776B3;
  --accent2: #7776B3;
  --numkey: #F5F5F5;
  --numkey2: #E0E0E0;
  --numkey-hover: #CCCCCC;
  --numkey-purchase: #7776B3;
  --numkey-purchase-hover: #6F6EAF;
}

*, *::before, *::after {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
}

html {
  font-size: 10px;
}

body {
  background-color: var(--bg);
  font-family: monospace;
  padding: 5px;
  display: flex;
    justify-content: center;
    align-items: center;
}

#grid-wrapper {
  display: grid;
    grid-template-rows: 10% 30% 10% 10% 40%;
    grid-template-columns: 75% 25%;
    grid-gap: 5px;
  height: 95vh;
  width: 98vw;
}

.container {
  background-color: var(--container-bg);
  border: 2px solid var(--border);
  width: 100%;
  overflow: auto;
}

.container h2 {
  background-color: var(--accent2);
  color: var(--container-bg);
  border-bottom: 3px solid var(--accent1);
  text-align: center;
  font-size: 2em;
}

.content-container {
  padding: 10px;
}

#title-container {
  grid-row: 1;
  grid-column: 1 / span 2; 
  background-color: var(--accent1);
  color: var(--container-bg)
}

#history-container {
  grid-row: 2 / span 3;  
  grid-column: 1;
}

#change-container {
  grid-row: 5;
  grid-column: 1;
}

#cid-container {
  grid-row: 2;
  grid-column: 2;
}

#price-container {
  grid-row: 3;
  grid-column: 2;
}

#cash-container {
  grid-row: 4 / span 2;
  grid-column: 2;
}

/* Title Window Styles */

#title-container {
  display: flex;
    justify-content: center;
    align-items: center;
}

#title {
  font-size: 5em;
}
/* Payment Window Styles */

#cash-container .content-container {
  height: 90%;
  display: flex;
    flex-direction: column;
    justify-content: space-evenly;
    align-items: center;
}

#price {
  font-size: 2em;
}

#cash {
  width: 250px;
  height: 25px;
  text-align: center;
}

#numpad {
  grid-row: 3;
  height: 250px;
  width: 250px;
  display: grid;
    grid-template-rows: 1fr 1fr 1fr 1fr;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-gap: 1px;
}

#numpad button{
  border: 1px solid var(--border);
  height: 100%;
}

.numkey {background-color: var(--numkey);}
.numkey2 {background-color: var(--numkey2);}

.numkey:hover, .numkey2:hover {
  background-color: var(--numkey-hover);
}
#numpad9 {grid-row: 1; grid-column: 3}
#numpad8 {grid-row: 1; grid-column: 2}
#numpad7 {grid-row: 1; grid-column: 1}
#numpad6 {grid-row: 2; grid-column: 3}
#numpad5 {grid-row: 2; grid-column: 2}
#numpad4 {grid-row: 2; grid-column: 1}
#numpad3 {grid-row: 3; grid-column: 3}
#numpad2 {grid-row: 3; grid-column: 2}
#numpad1 {grid-row: 3; grid-column: 1}
#numpad0 {grid-row: 4; grid-column: 1 / span 2}
#numpad-dot {grid-row: 4; grid-column: 3;}

#purchase-btn {
  grid-row: 3 / span 2; 
  background-color: var(--numkey-purchase);
  border: 1px solid var(--border);
  color: var(--container-bg);
}

#purchase-btn:hover {
  background-color: var(--numkey-purchase-hover);
}

/* History Window Styles */

#history {
  width: 100%;
  text-align: center;
}

/* Item Window Styles */

#item-container .content-container {
  padding: 5px;
}

#item-info-container {  
  width: 100%;
  text-align: center;
}

/* CID Window Styles */

#cid {
  width: 100%;
  text-align: center;
}

/* Change Window Styles */

/* Responsive Design */
@media only screen and (max-width: 1000px) {
  #title {font-size: 2.5em}
  .content-container {padding: 5px;}
  .container h2 {font-size: 1.5em;}
  table {font-size: 1.2em;}
  #price {font-size: 1.2em}
  #numpad {width: 200px; height: 200px;}
  #cash {width: 200px;}
}

@media only screen and (max-width: 600px) {
  #title {font-size: 1.5em;}
  #grid-wrapper {
    height: auto;
    display: flex;
      flex-direction: column;
  }
}

JavaScript

const userCash = document.getElementById("cash");
const purchaseBtn = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");
const cidDOM = document.querySelectorAll(".cid");
const itemDOM = document.getElementById("item-info");
const priceDOM = document.getElementById("price")
let price = 3.26;
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 changeDueStatus = "";
let cashDenomination = {}
let hasEnoughChange = false;

const cidCalculate = () => {
  let total = 0;
  for (let i = 0; i < cid.length; i++) {
    total = Number(total.toPrecision(6));
    total += cid[i][1];
  }
  return total
}

purchaseBtn.addEventListener("click", () => cashRegister(cidCalculate(), userCash.value, Number((userCash.value - price).toPrecision(6))));

const cashRegister = (cidTotal, cash, change) => {
  console.log(cidTotal, cash, change);
  if (change < 0) {
    alert("Customer does not have enough money to purchase the item");
    return;
  } else if (change > cidTotal) { 
      changeDueStatus = "Status: INSUFFICIENT_FUNDS";
      updateDisplay();
      return;
  } else if (change === 0) {
      changeDueStatus = "No change due - customer paid with exact cash";
      updateDisplay();
      return;
  } else if (change >= 0) {
      denominateCash(change);
      if (hasEnoughChange && cidTotal - change === 0) {
        changeDueStatus = "Status: CLOSED";
      } else if (hasEnoughChange) {
        changeDueStatus = "Status: OPEN";
      } else {
        changeDueStatus = "Status: INSUFFICIENT_FUNDS";
      }
      updateDisplay();
    return;
  }
}

const correctCID = () => {
  for (let i = 0; i < cid.length; i++) {
    cid[i][1] = Number(cid[i][1].toPrecision(6));
  }
}

const denominateCash = (change) => {
  correctCID();
  change = Number(change.toPrecision(4));
  console.log(change)
  if (change >= 100 && cid[8][1] >= 100) {
    cid[8][1] -= 1;
    updateCashDenomination("ONE HUNDRED", 100);
    denominateCash(change - 100);
  } else if (change >= 20 && cid[7][1] >= 20) {
    cid[7][1] -= 20;
    updateCashDenomination("TWENTY", 20);
    denominateCash(change - 20);
  } else if (change >= 10 && cid[6][1] >= 10) {
    cid[6][1] -= 10;
    updateCashDenomination("TEN", 10);
    denominateCash(change - 10);
  } else if (change >= 5 && cid[5][1] >= 5) {
    cid[5][1] -= 5;
    updateCashDenomination("FIVE", 5);
    denominateCash(change - 5);
  } else if (change >= 1 && cid[4][1] >= 1) {
    cid[4][1] -= 1;
    updateCashDenomination("ONE", 1);
    denominateCash(change - 1);
  } else if (change >= 0.25 && cid[3][1] >= 0.25) {
    cid[3][1] -= 0.25;
    updateCashDenomination("QUARTER", 0.25);
    denominateCash(change - 0.25);
  } else if (change >= 0.1 && cid[2][1] >= 0.1) {
    cid[2][1] -= 0.1;
    updateCashDenomination("DIME", 0.1);
    denominateCash(change - 0.1);
  } else if (change >= 0.05 && cid[1][1] >= 0.05) {
    cid[1][1] -= 0.05;
    updateCashDenomination("NICKEL", 0.05);
    denominateCash(change - 0.05);
  } else if (change >= 0.01 && cid[0][1] >= 0.01) {
    cid[0][1] -= 0.01;
    updateCashDenomination("PENNY", 0.01);
    denominateCash(change - 0.01);
  } else if (change === 0) {
    console.log(change, cashDenomination, "true");
    hasEnoughChange = true;
    return;
  } else {
    console.log(change, "false")
    hasEnoughChange = false;
    undoDenomination()
    return;
  }
}

const undoDenomination = () => {
  for (let [key, value] of Object.entries(cashDenomination)) {
    for (let i = 0; i <= 8; i++) {
      if (cid[i].includes(key)) {
        cid[i][1] += value;
      } 
    }
    cashDenomination = {};
  }
}

const updateCashDenomination = (type, value) => {
  cashDenomination[type] = cashDenomination[type] 
    ? Number((cashDenomination[type] + value).toPrecision(6))
    : value; 
}

const updateDisplay = () => {
  changeDue.innerText = "";
  for (let i = 0; i <= 8; i++) {
    cidDOM[i].innerText = `\$${cid[i][1]}`;
  }

  changeDue.innerText = changeDueStatus;
  for (let [key, value] of Object.entries(cashDenomination)) {
    changeDue.innerText += ` ${key}: \$${value}`
  }
}

The tests run without reloading your program in between. So one way to stress test your code is to load it up once then just enter some cash values in sequence that are designed to test different scenarios (making sure to not reload the code each time you try).

So for eg, let’s say the current code is loaded, maybe some values to try running in sequence can be:

335.26 (the status should be open and the change should be sorted from high to low)
5 (insufficient fund result)
3.67 (should give closed status and exact change)

1 Like

I was able to pinpoint the bug and figure out the next step to take on my code thanks to your explanation. Thank you!

1 Like