Build a Cash Register

Hi there!, I’m having an issue with 2 lasts tests:

  • 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".

  • Failed: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.

I’m very confused and stucked as well

Here’s my codes:

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

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

function checkCashRegister(price, cash, cid) {
  let changeDue = Math.round((cash - price) * 100) / 100;
  const totalCid = Math.round(cid.reduce((sum, [, amount]) => sum + amount, 0) * 100) / 100;

  if (totalCid < changeDue) {
    return { status: "INSUFFICIENT_FUNDS", change: [] };
  }

  if (totalCid === changeDue) {
    return { status: "CLOSED", change: cid };
  }

  const change = [];
  const reversedCid = [...cid].reverse();

  for (let [unit, amount] of reversedCid) {
    const unitValue = currencyUnit[unit];
    let unitTotal = 0;

    while (changeDue >= unitValue && amount > 0) {
      changeDue = Math.round((changeDue - unitValue) * 100) / 100;
      amount -= unitValue;
      unitTotal += unitValue;
    }

    if (unitTotal > 0) {
      change.push([unit, unitTotal]);
    }
  }

  if (changeDue > 0) {
    return { status: "INSUFFICIENT_FUNDS", change: [] };
  }

  return { status: "OPEN", change: change };
}

document.getElementById('purchase-btn').addEventListener('click', function() {
  const cashInput = parseFloat(document.getElementById('cash').value);
  const changeDueElement = document.getElementById('change-due');

  if (cashInput < price) {
    alert("Customer does not have enough money to purchase the item");
    changeDueElement.textContent = "";
    return;
  }

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

  const result = checkCashRegister(price, cashInput, cid);
  let output = `Status: ${result.status}`;

  if (result.status === "CLOSED") {
    output += " " + result.change.map(([unit, amount]) => `${unit}: $${amount.toFixed(2)}`).join(' ');
  } else if (result.status === "OPEN") {
    output += " " + result.change.map(([unit, amount]) => `${unit}: $${amount.toFixed(2)}`).join(' ');
  }

  changeDueElement.textContent = output.trim();
});

Have you tried testing the first failing testcase yourself? What output is placed in the #change-due element? Does it match the expectation?

I went ahead and tested the first failing test case. Here’s what I did:

[
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100]
]

I don’t know why the output didn’t match the expectation.

this doesn’t match the testcase though?

Definitely,… Could you please provide any guidance on what might be causing this discrepancy?

you haven’t answered me yet? I was wondering if you had tested your code with the specific testcase that was failing?
If yes, what value was getting printed to #change-due?
Was it the same as the testcase expected?

I tested the code, and I’m happy to report that my tests worked. I’ve fixed the bug, and now the output in #change-due matches the expected result.