Build cash register

i think it’s error in checking, im complete the task, but its not checked, btw its has 2 task and it’s complitly same task and both can’t be done

if you want help you need to share your code

<!DOCTYPE html>
<html>
<head>
  <title>Cash Register</title>
</head>
<body>
  <h1>Cash Register</h1>
  <div id="change-due"></div>
  <!-- Change display div -->
  <p id="total"></p>
  <input type="number" id="cash" placeholder="Cash Provided">
  <button id="purchase-btn" >Calculate Change</button>
  <div id="cash-in-drawer"></div>
   
  <script>
    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]
    ];

    cid = [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]

    const cashProvided = document.getElementById('cash')
    const total = document.getElementById('total');
    total.textContent = `Total: $${price.toFixed(2)}`;
    const changeDisplay = document.getElementById('change-due')
    const purchaseBtn = document.getElementById('purchase-btn')
    const cashInDrawer = document.getElementById('cash-in-drawer');
    cashInDrawer.innerHTML = `<p>${cid}</p><br>`
    let status = "OPEN"
    let availableChange = []
    
    const roundUpToTwoDecimals = num => {
  return Math.round(num * 100) / 100;
}

    const calculateChange = () => {
  const changeDue = (Number(cashProvided.value) - price);
  const reversedCid = cid.slice().reverse();
  const denominations = [
    ["ONE HUNDRED", 100],
    ["TWENTY", 20.00],
    ["TEN", 10],
    ["FIVE", 5],
    ["ONE", 1],
    ["QUARTER", 0.25],
    ["DIME", 0.1],
    ["NICKEL", 0.05],
    ["PENNY", 0.01]
  ];
  
  let totalCashAvailable = reversedCid.reduce((acc, cur) => acc + cur[1], 0);
  let remainingChangeDue = roundUpToTwoDecimals(changeDue)  
  let closedStatusReached = false;
  let totalUsedAmount = 0
  for (let i = 0; i < reversedCid.length; i++) {
    const currency = reversedCid[i];
    const currencyUnit = currency[0];
    let currencyAmount = currency[1];
    const cidLeft = Math.ceil(currencyAmount / denominations[i][1])
    const numOfDenomination = Math.floor(remainingChangeDue / denominations[i][1]);
    
    
    if(changeDue > totalCashAvailable){
      status = " INSUFFICIENT_FUNDS";
      updateUi()
      break;
    } else if (numOfDenomination > 0 && cidLeft > 0) {
      if(changeDue === totalCashAvailable){
        status = "CLOSED"
      }
      const usedAmount = Math.min(numOfDenomination, cidLeft) * denominations[i][1];
      console.log("change" + remainingChangeDue + "used amount" + usedAmount)
      console.log("amountcurrency" + currencyAmount + "used amount" + usedAmount)
      remainingChangeDue = roundUpToTwoDecimals(remainingChangeDue - usedAmount);
      currencyAmount -= roundUpToTwoDecimals(currencyAmount - usedAmount);
      totalUsedAmount += usedAmount
       const changes = `<p>${currencyUnit}: $${usedAmount}</p>`;
      availableChange.push(changes)
      totalCashAvailable -= totalUsedAmount
      totalUsedAmount = 0
    }

    updateUi();
  }
}
    


const checkReturn = () =>{
  if(Number(cashProvided.value) === price){
     changeDisplay.textContent = "No change due - customer paid with exact cash"
  } else if(Number(cashProvided.value) < price){
     alert('Customer does not have enough money to purchase the item')
  } else {
    calculateChange()
  }
}


const updateUi = () => {
  changeDisplay.innerHTML = `<p>Status: ${status}</p>
${availableChange.join(``)}`
}

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

purchaseBtn.addEventListener("keydown", (e)=>{
  if(e === "Enter"){
    checkReturn()
    
  }
})
  </script>
</body>
</html>

im sure im already complete the task

I’ve edited your code for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (').

How to test that everything works:

you should reassign price and cid down here.

for example

price = 19.5;
cid = [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]
  </script>

and then try your app. in this way you should notice if your app works with the way the tests are structured

2 Likes

i’ve made new code and it works perfectly, but i just learn how javascript works, it works from top to bottom, why i should declare the variable again in the bottom of the code? and why should cash register re assign cid value?.. i know it just for project training, but real life cash register is put money in cash drawer, and transaction until the money is 0, no need re assign the money you put to it unleash you add more money to cid.

please give me insight
note: my code stuck in the same problem too

top to bottom, yes, the tests are like extra code added at the bottom that call your functions, so not declaring but reassigning cid and price at the bottom show if your code can work.

there is an other reason here, function purity: having global variables that your function change is against this concept, a function to be a pure function can’t have side effects, also side effects impact the reusability of the function. For the tests to work, your function has to be perfectly reusable, and a pure function, other than have correct logic and code that reach the goal.

1 Like

i see, you right, maybe you should add note in test

  1. declare your cid and price in the bottom for
  2. make the function more reuseable.

bcs when i see cashRegister in freeCodeCamp, all i can think is how to make code to achieve this, i don’t think to reassign the cid, bcs the example not do it

thanks for the insight

you don’t need to declare cid and price at the bottom, they just need to be in the global space. Changing their value after all the code is just a way to test

can you give me insight, i think my code was better

<div class="container">
    <h1>Cash Register</h1>
    <div id="change-due"></div>
    <p id="total"></p>
    <input type="number" id="cash" placeholder="Cash Provided">
    <button id="purchase-btn">Calculate Change</button>
    <div id="cash-in-drawer"></div>
  </div>
const cashProvided = document.getElementById('cash');
const total = document.getElementById('total');
const changeDisplay = document.getElementById('change-due');
const purchaseBtn = document.getElementById('purchase-btn');
const cashInDrawer = document.getElementById('cash-in-drawer');
const denominations = [
  ["ONE HUNDRED", 100],
  ["TWENTY", 20.00],
  ["TEN", 10],
  ["FIVE", 5],
  ["ONE", 1],
  ["QUARTER", 0.25],
  ["DIME", 0.1],
  ["NICKEL", 0.05],
  ["PENNY", 0.01]
];

//function
const roundUpToTwoDecimals = num => {
  return Math.round(num * 100) / 100;
}

// let variable
let availableChange = [];
let price = 19.50;
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 roundTotalCash = roundUpToTwoDecimals(cid.reduce((acc, cur) => acc + cur[1], 0));
console.log("initial totalCash: "+ roundTotalCash)
let statusText = "OPEN";

// initialize display UI
total.textContent = `Total: $${price.toFixed(2)}`;
cashInDrawer.innerHTML = `<p>${cid.map(entry => `${entry[0]}: $${entry[1].toFixed(2)}`).join('<br>')}</p>`;

const calculateTotalCash = () => {
  const roundChange = roundUpToTwoDecimals(Number(cashProvided.value));
  console.log("totalCash roundChange: " + roundChange)
  console.log("totalCash roundTotalCash: " + roundTotalCash)
  let emptyCid = roundChange - price - roundTotalCash
      
  if (roundChange > roundTotalCash) {
    statusText = "INSUFFICIENT_FUNDS";
  } else if(roundTotalCash === 0){
    statusText = "CLOSED"
  } 
  console.log(statusText)
  updateUi();
}

const usedChange = (change) => {
  let usedCashArr = [];
  let roundChange = roundUpToTwoDecimals(change);
  let totalUsedAmount = 0;

  let reversedCid = [...cid].reverse();

  for (let i = 0; i < reversedCid.length; i++) {
    const currency = reversedCid[i];
    const currencyUnit = currency[0];
    let currencyAmount = roundUpToTwoDecimals(currency[1]);
    const cidLeft = Math.ceil(currencyAmount / denominations[i][1]);
    const numOfDenomination = Math.floor(roundChange / denominations[i][1]);
    const usedAmount = Math.min(numOfDenomination, cidLeft) * denominations[i][1];
    const roundUserAmount = roundUpToTwoDecimals(usedAmount);

    roundChange = roundUpToTwoDecimals(roundChange - roundUserAmount);

    if (usedAmount > 0) {
      usedCashArr.push({ currencyUnit, value: roundUserAmount });
      totalUsedAmount = roundUpToTwoDecimals(totalUsedAmount + roundUserAmount);
    }

    if (roundChange <= 0) {
      break;
    }
  }
  
  console.log("total Used Amount: "+ totalUsedAmount)
  roundTotalCash = roundUpToTwoDecimals(roundTotalCash - totalUsedAmount);
  console.log("totalCash after - total usedAmount: " + roundTotalCash)
  // Convert objects to arrays and push to availableChange
  usedCashArr.forEach(e => {
    const unit = e.currencyUnit;
    const value = e.value;
    availableChange.push([unit, value]);
  });
  updateUi();
  updateTotalCid(usedCashArr);
};
    
const updateTotalCid = (arr) => {
  let updateTotalArr = [];
  const updatedCid = [...cid].reverse();

  // Create a map for quick lookup of used change amounts
  const usedChangeMap = new Map();
  arr.forEach(usedEntry => {
    usedChangeMap.set(usedEntry.currencyUnit, usedEntry.value);
  });

  // Deduct used amounts from updatedCid
  updatedCid.forEach(currency => {
    const currencyUnit = currency[0];
    const currencyAmount = currency[1];
    if (usedChangeMap.has(currencyUnit)) {
      const usedAmount = usedChangeMap.get(currencyUnit);
      const cidSubtract = roundUpToTwoDecimals(currencyAmount - usedAmount);
      updateTotalArr.push([currencyUnit, cidSubtract]);
    } else {
      updateTotalArr.push([currencyUnit, currencyAmount]);
    }
  });
  // Assign updatedCid back to cid
  cid = updateTotalArr.reverse(); // reverse back to original order

  // Update cashInDrawer with the updated cid values
  cashInDrawer.innerHTML = `<p>${cid.map(entry => `${entry[0]}: $${entry[1].toFixed(2)}`).join('<br>')}</p>`;
}

console.log("cid before :"+cid)

const updateUi = () => {
  changeDisplay.innerHTML = `<h3>Status: ${statusText}</h3>
  <p>${availableChange.map(entry => `${entry[0]}: $${entry[1].toFixed(2)}`).join('<br>')}</p>`;
  cashProvided.value = '';
}

const checkReturn = () => {
  availableChange = []; // Clear availableChange at the start of checkReturn
  const cashProvidedValue = Number(cashProvided.value);

  if (cashProvidedValue === price) {
        changeDisplay.textContent = "No change due - customer paid with exact cash";
  } else if (cashProvidedValue < price) {
        alert('Customer does not have enough money to purchase the item');
  } else {
        const change = cashProvidedValue - price;
        calculateTotalCash()
        if (statusText === "INSUFFICIENT_FUNDS") {
            changeDisplay.innerHTML = `<h3>Status: ${statusText}</h3>`
            statusText = "OPEN"
        } else {
            usedChange(change);
            if(roundTotalCash === 0){
                calculateTotalCash();
            }
        }
    }
}
purchaseBtn.addEventListener("click",()=>{
  checkReturn();
  console.log("round total cash after checkReturn: " +  roundTotalCash);
  console.log("cid after :" + JSON.stringify(cid));
  
});

cashProvided.addEventListener("input", () => {
  changeDisplay.innerHTML = ""; // Clear the change-due display
});

cashProvided.addEventListener("keydown", (e) => {
  if (e.key === "Enter") {
    checkReturn();
    console.log("round total cash after checkReturn: " +  roundTotalCash);
    console.log("cid after :" + JSON.stringify(cid));
  }
});

thanks! My code was “working” with the same inputs of the tests, but I wasnt reseting variables like total price and some tweek of decimal numbers of cid. Finally passed the tests!