Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

Hey guys,
I have trouble finishing this project. The tests keep failing and I dont know exactly. For instance: There is a test case where the price is set to 19.5, the cash given is supposed to be 20 but the Cash-in-Drawer is insufficient . The test says that the text in the output element should be: “Status: INSUFFICIENT_FUNDS”. So I assigned the cid and the price to the values mentioned above and my website returns the wanted text. I dont get why the test case fails if both strings are equal.

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" />
    <title>CashRegister</title>
    <link rel="stylesheet" href="styles.css">
  </head>
  <body>
    <div class="container">
      <h1>Cash Register</h1>
      <p id="change-due"></p>
      <label for="cash">Enter cash from customer: </label>
      <input type="number" id="cash" />
      <button id="purchase-btn">Change</button>
      <p id="price"></p>
    </div>
    <script src="script.js"></script>
  </body>
</html>
/* file: script.js */
const priceElement = document.getElementById("price");
const cash = document.getElementById("cash");
const changeBtn = document.getElementById("purchase-btn");
const changeDue = document.getElementById("change-due");

let price = 19.5;
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]];

window.addEventListener("load", () => (priceElement.innerText = price));

const determineValue = (currencyName) => {
  switch (currencyName) {
    case "PENNY":
      return 0.01;
    case "NICKEL":
      return 0.05;
    case "DIME":
      return 0.1;
    case "QUARTER":
      return 0.25;
    case "ONE":
      return 1;
    case "FIVE":
      return 5;
    case "TEN":
      return 10;
    case "TWENTY":
      return 20;
    case "ONE HUNDRED":
      return 100;
    default:
      return 1;
  }
};

class CashRegister {
  constructor(cid) {
    this.register = cid;
    this.status = "OPEN";
    this.hand = {};
  }

  getAmount(currency) {
    const entry = this.register.find((el) => el[0] === currency);
    return Number((entry[1] / determineValue(entry[0])).toFixed(2));
  }

  getFunds() {
    return Number(
      this.register.reduce((acc, el) => (acc += el[1]), 0).toFixed(2)
    );
  }

  isEmpty() {
    return this.getFunds() === 0;
  }

  putHandBack() {
    for (const [currency, amount] of Object.entries(this.hand)) {
      if (["QUARTER", "DIME", "NICKEL", "PENNY"].includes(currency)) {
        this.register.find((el) => el[0] === currency)[1] += Number(
          (amount * determineValue(currency)).toFixed(2)
        );
      } else {
        this.register.find((el) => el[0] === currency)[1] +=
          amount * determineValue(currency);
      }
    }
    this.hand = {};
  }

  formatHand() {
    let returnArray = [`Status: ${this.status}`];
    for (const [key, value] of Object.entries(this.hand)) {
      if (value === 0) {
        continue;
      }
      if (["QUARTER", "DIME", "NICKEL", "PENNY"].includes(key)) {
        returnArray.push(
          `${key}: $${Number((value * determineValue(key)).toFixed(2))}`
        );
      } else {
        returnArray.push(`${key}: $${value * determineValue(key)}`);
      }
    }
    this.hand = {};
    return returnArray.join(" ");
  }

  takeCash(currency, amount) {
    switch (currency) {
      case "ONE HUNDRED":
        this.register[8][1] -= amount;
        break;
      case "TWENTY":
        this.register[7][1] -= amount;
        break;
      case "TEN":
        this.register[6][1] -= amount;
        break;
      case "FIVE":
        this.register[5][1] -= amount;
        break;
      case "ONE":
        this.register[4][1] -= amount;
        break;
      case "QUARTER":
        this.register[3][1] -= amount;
        break;
      case "DIME":
        this.register[2][1] -= amount;
        break;
      case "NICKEL":
        this.register[1][1] -= amount;
        break;
      case "PENNY":
        this.register[0][1] -= amount;
        break;
      default:
        return;
    }
  }

  computeCurrency(money, currency) {
    const value = determineValue(currency);
    const currentAmount = this.getAmount(currency);
    const requiredAmount = Math.floor(money / value);
    let leftover = money;

    if (leftover >= value) {
      const amount =
        requiredAmount <= currentAmount ? requiredAmount : currentAmount;
      leftover -= amount * value;
      this.takeCash(currency, amount * value);
      this.hand[currency] = amount;
    }
    return leftover;
  }

  change(receivedMoney) {
    this.status = this.status === "CLOSED" ? "CLOSED" : "OPEN";
    if (this.status === "CLOSED") {
      changeDue.innerText = "Status: CLOSED";
      return;
    }

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

    // calculation
    const difference = Number((receivedMoney - price).toFixed(2));
    let leftover = difference;
    const register = this.register.slice();
    register
      .reverse()
      .map((el) => el[0])
      .forEach((el) => {
        leftover = Number(this.computeCurrency(leftover, el).toFixed(2));
        console.log("leftover", leftover);
      });
    if (leftover === 0 && this.isEmpty()) {
      this.status = "CLOSED";
    } else if (leftover === 0) {
      this.status = "OPEN";
    } else {
      this.status = "INSUFFICIENT_FUNDS";
    }
    console.log("hand", this.hand);

    // output
    if (this.status === "INSUFFICIENT_FUNDS") {
      changeDue.innerText = "Status: INSUFFICIENT_FUNDS";
      this.putHandBack();
      return;
    } else {
      changeDue.innerText = this.formatHand();
    }
    return;
  }
}

const cashRegister = new CashRegister(cid);
changeBtn.addEventListener("click", () => {
  const money = Number(cash.value);
  cashRegister.change(money);
});
/* file: styles.css */
* {
  padding: 0;
  margin: 0;
}

.container {
  margin: 0 auto;
  width: min(80%, 1000px);
  background-color: rgb(10, 10, 77);
  color: white;
  padding: 10px;
  text-align: center;
}

label {
  display: block;
  padding: 5px;
}

input {
  display: block;
  margin: 10px auto 10px;
}

button {
  background-color: rgb(238, 202, 84);
  border: 2px solid orange;
  padding: 5px;
}

#price::before {
  content: "Price: $";
}

#price {
  padding: 10px;
  color: rgb(224, 47, 47);
}

#output {
  padding: 5px;
}

Your browser information:

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

Challenge Information:

Build a Cash Register Project - Build a Cash Register

The behaviour of the tests is akin of adding

price = ...
cid = ...

as last lines in your code, and then clicking the button.
The app keeps running between each test, it doesn’t start from the beginning each time.
Does your code manage this?

1 Like

Don’t think it does.

constructor(cid) {
    this.register = cid;
    this.status = "OPEN";
    this.hand = {};
  }

I use an object all the time so I think I would need to reassign the the register each time the cid is changed. Please correct me if I’m wrong. I thought the tests would work different so an OO approach does seem to be harmful for this (I just wanted to try it out in order to practise the syntax). Is there any way to dynamically reassign my register in the CashRegister class every time cid and price get a new value ?

you can use the button click as a trigger to get new values

Thanks a lot for the tips. I got it now by just moving the creation of the object into the Event Listener. I appreciate the help a lot! If you have free time can you have a quick look if there are any No-Gos in my JS Code ?

you can create a post in Code Feedback with all your updated code if you want feedback