Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

My code does not pass the tests despite giving the correct output.

Since the last few lessons were OOP, I took that approach for this problem and it seems to work well, however the last 6 tests on the page do not pass, but my desired output when testing myself matches the tests. Can someone please shed some light as to why my code cannot pass the last 6 test cases?

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>Cash Register</title>
</head>
<body>
  <div class="container main">
    <h1>Cash Register Project</h1>
    <label for="cash">Enter cash from customer</label>
    <input type="number" id="cash" name="cash">
    <button type="button" id="purchase-btn">Purchase</button>
  </div>

  <div id="change-due">
  </div>

  <div class="register" id="register">
  </div>
  <script src="script.js"></script>
</body>
</html>
/* file: styles.css */
:root {
  --jet: #2E2F2F;
  --azure: #EBF4F5;
  --powder-blue: #B5C6E0;
}

html {
  min-height: 100%;
}

body {
  font-family: Arial, Helvetica, sans-serif;
  color: var(--jet);
  background-image: linear-gradient(to bottom right, var(--azure), var(--powder-blue));
  background-repeat: no-repeat;
  text-align: center;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1em;
}

.main {
  margin-bottom: 1em;
}

input {
  border: none;
  border-radius: 10px;
  padding: 0.6em 1em;
}

button {
  background-color: var(--jet);
  color: var(--azure);
  font-weight: 800;
  border: none;
  border-radius: 10px;
  padding: 0.6em 1em;
  cursor: pointer;
}

p {
  margin: 2px;
}
/* file: script.js */
let price = 19.5;
let cid = [
  ['PENNY', 0.1],
  ['NICKEL', 0],
  ['DIME', 0],
  ['QUARTER', 0],
  ['ONE', 0],
  ['FIVE', 0],
  ['TEN', 0],
  ['TWENTY', 0],
  ['ONE HUNDRED', 0]
];

const currencyUnit = {
  "PENNY": 0.01,
  "NICKEL": 0.05,
  "DIME": 0.1,
  "QUARTER": 0.25,
  "ONE": 1,
  "FIVE": 5,
  "TEN": 10,
  "TWENTY": 20,
  "ONE HUNDRED": 100
};

const cash = document.querySelector("#cash");
const purchaseBtn = document.querySelector("#purchase-btn");
const changeDue = document.querySelector("#change-due");
const register = document.querySelector("#register");

class CashRegister {
  constructor(cid) {
    this.cid = cid.slice().reverse(); //makes more sense to always try highest denominations first
    this.status = "OPEN";
  }

  getTotalCash() {
    const total = this.cid.reduce((total, currency) => total + currency[1], 0);
    return parseFloat(total.toFixed(2));
  }

  getCashByDenomination(denomination) {
    const currency = this.cid.find(item => item[0] === denomination);
    return currency ? currency[1] : 0;
  }

  getCountByDenomination(denomination) {
    const cashByDenomination = this.getCashByDenomination(denomination);
    return Math.floor(cashByDenomination / currencyUnit[denomination]);
  }

  // calculate difference between cash and price and return an object of currency and corresponding amount, i.e. 
  getChange(cash) {
    let change = Number((cash - price).toFixed(2));

    if (change > this.getTotalCash()) {
      this.status = "INSUFFICIENT_FUNDS";
      return {};
    }

    const changeObj = {};

    this.cid.forEach(currency => {
      const denomination = currency[0];
      const denominationValue = currencyUnit[denomination];

      while(this.getCountByDenomination(currency[0]) > 0 && change >= denominationValue) {
        change -= denominationValue;
        change = Number(change.toFixed(2));
        currency[1] -= denominationValue;
        currency[1] = Number(currency[1].toFixed(2));
        changeObj[denomination] = (changeObj[denomination] || 0) + denominationValue;
        changeObj[denomination] = Number(changeObj[denomination].toFixed(2));
      }
    });

    if (change > 0) {
      this.status = "INSUFFICIENT_FUNDS";
      return {};
    }

    if (this.getTotalCash() > 0) {
      this.status = "OPEN";
    } else {
      this.status = "CLOSED"
    }

    return changeObj;
  }
}

const cashRegister = new CashRegister(cid);

const updateChangeDue = (status, changeObj) => {
  changeDue.innerHTML = "";
  changeDue.innerHTML += `<p>Status: ${status}</p>`;
  for (const [key, value] of Object.entries(changeObj)) {
    changeDue.innerHTML += `<p>${key}: $${value}</p>`;
  }
}

const updateRegisterAmount = () => {
  register.innerHTML = "<h2>Cash left in register</h2>";

  cid.forEach(money => {
    register.innerHTML += `<p>${money[0].toLowerCase()}: $${money[1]}</p>`;
  })
};

updateRegisterAmount();

purchaseBtn.addEventListener("click", () => {

  if (!cash.value) return; 

  if (cash.value < price) {
    alert("Customer does not have enough money to purchase the item");
    return;
  }

  if (cash.value == price) {
    changeDue.textContent = "No change due - customer paid with exact cash"
    return;
  }

  const changeGiven = cashRegister.getChange(cash.value);
  updateRegisterAmount();
  updateChangeDue(cashRegister.status, changeGiven);
});

Your browser information:

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

Challenge Information:

Build a Cash Register Project - Build a Cash Register

this code is initialized in the global scope.
This means it runs exactly once even though the tests will update the cid variable multiple times.
This is probably one reason why your results do not match the testcase results.

Thank you that was it! All I needed to do was to declare the cash register object in the button event listener instead of globally declaring it.

1 Like