Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

My implementation seems to do what is requiered however I am still failing

Your code so far

<!-- file: index.html -->

/* file: script.js */

/* file: styles.css */

Your browser information:

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

Challenge Information:

Build a Cash Register Project - Build a Cash Register

Hi @weisswesley22 , welcome to the forum

Please update the message to include your code. The code was too long to be automatically inserted by the help button.

When you enter a code, 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 (').

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

const denominations = [
  ['PENNY', 0.01],
  ['NICKEL', 0.05],
  ['DIME', 0.1],
  ['QUARTER', 0.25],
  ['ONE', 1],
  ['FIVE', 5],
  ['TEN', 10],
  ['TWENTY', 20],
  ['ONE HUNDRED', 100]
]


const priceSpan = document.getElementById('price');
const cashPaid = document.getElementById('cash');
const changeDisplay = document.getElementById('change-due');
const screen = document.getElementById('screen');
const purchaseBtn = document.getElementById('purchase-btn');
let giveChange = false;
let hasRun = false;
priceSpan.innerText = `$${price}`;

let totalCid = Number(cid.reduce((acc, el) => el[1] + acc, 0)
                  .toFixed(2));

let balance = 0;

const stats = (bal, initTotalCid, initBal) => {
  totalCid = Number(cid.reduce((acc, el) => el[1] + acc, 0)
                  .toFixed(2));
  
  if((totalCid === 0 && bal === 0 && giveChange) || (totalCid === 0 && bal === 0 && giveChange && initBal === initTotalCid))
    return '<strong>Status</strong>: CLOSED<br/>';
  else if(bal == 0) 
    return '<strong>Status</strong>: OPEN<br/>';
  else if( bal > 0)
   return '<strong>Status</strong>: INSUFFICIENT_FUNDS';
  else 
    return;
   
}

const hasSuitableLowerDenominations = (bal, change) => {
  const changeArr = change.map((el) => [...el]);

  for (let i = 0; i < changeArr.length; i++) {
    if (denominations[i][1] < bal) {
      while (changeArr[i][1] > 0) {
        bal = Number((bal - changeArr[i][1]).toFixed(2));
        changeArr[i][1] = Number((changeArr[i][1] - changeArr[i][1]).toFixed(2));
      }
    }

    if (bal <= 0) return true;
  }

  return false;
}

const check = (paid) => {
  balance = Number((paid - price).toFixed(2));
  if(paid < price) {
    alert('Customer does not have enough money to purchase the item');
    return;
  } else if(paid === price) {
    changeDisplay.innerHTML = 'No change due - customer paid with exact cash';
    return;
  }
  
  if(totalCid < balance || balance < 0 || hasSuitableLowerDenominations(balance, cid) == false)
    giveChange = false; 
  else if(totalCid === balance) 
    giveChange = true; 
  else if(totalCid > balance) 
    giveChange = true;
  
  balanceCalculator(paid);
}

const balanceCalculator = (paid) => {
  let index = cid.length - 1;
  let currentChange = cid.slice();
  const ogBalance = Number((paid - price).toFixed(2));
  const ogTotalCid = totalCid;
  hasRun = true;

  let denominationCount = {};
  while(balance > 0 && index >= 0 && giveChange) {
    while(balance >= denominations[index][1] && balance - denominations[index][1] >= 0 && currentChange[index][1] >= denominations[index][1] ) {
      balance = Number((balance - denominations[index][1]).toFixed(2));
      currentChange[index][1] = Number((currentChange[index][1] - denominations[index][1]).toFixed(2));
      if(denominationCount[denominations[index][0]])
        denominationCount[denominations[index][0]] ++;
      else
        denominationCount[denominations[index][0]] = 1;
    }
    if(index > 0)
      index--;

  }

  cid = currentChange;
  totalCid = Number(cid.reduce((acc, el) => el[1] + acc, 0)
                  .toFixed(2));
  updateUI(denominationCount, ogTotalCid, ogBalance);
}

const updateUI = (obj, originalTotalCid, originalBalance) => {
  changeDisplay.innerHTML = '';
  screen.innerHTML = '';

  if(hasRun) {
    changeDisplay.innerHTML = stats(balance, originalTotalCid, originalBalance);
  }
  if(obj && giveChange)
    Object.keys(obj).forEach((key)=> {
      let value;
      denominations.forEach((item, index) => {
        if(key === item[0]) {
          value = denominations[index][1];
          return;
        }
      })

      changeDisplay.innerHTML +=  `<strong>${key}</strong>: $${Number((value * obj[key]).toFixed(2))}<br/>`;
    })
  console.log(originalTotalCid, originalBalance);
  console.log(changeDisplay.innerHTML);

  cid.forEach((el)=> {
    const coinDiv = document.createElement('div');
    coinDiv.innerHTML = `<strong>${el[0]}</strong> : $${el[1]}`;
    screen.append(coinDiv);
  })
  const totalDiv = document.createElement('div');
  totalDiv.innerHTML = `<strong>TOTAL</strong>: $${totalCid}`;
  screen.append(totalDiv);
}

updateUI();

purchaseBtn.addEventListener('click', () => {
  check(Number(cashPaid.value));
})

cashPaid.addEventListener('keydown', (e) => {
  if(e.key === 'Enter')
    check(Number(cashPaid.value));
})

The code is above

can you also share your html please?

/*Psalms 37:21 The wicked borrow and do not repay, but the righteous give generously.*/
* {
  margin: 0;
}

body{
  background: radial-gradient(ellipse at bottom, #0d1d31 10%, #0c0d13 100%);
  height: 100vh;
  width: 100vw;
  color: #f2f2f2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.register-top {
  width: 80vw;
  margin-bottom: 10px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
}

#screen {
  background: #f2f2f2;
  border-radius: 10px;
  padding: 10px;
  width: 32vw;
  height: 45vh;
  color: #0d1d31;
}

#cash {
  background: transparent;
  border: 0;
  border-bottom: 2px solid gray;
  color: #f2f2f2;
}

.monies {
  height: 45vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
#change-due {
  width: 40vw;
  height: 20vw;
  background: #f2f2f2;
  border-radius: 10px;
  color: #0d1d31;
  overflow-y: scroll;
  padding: 5px;
}

#purchase-btn {
  background: #f2f2f2;
  border: 0;
  border-radius: 3px;
  color: #0d1d31;
  padding: 2px;
}

@media (max-width: 560px) {
  body {
    padding: 15px 0;;
    overflow-x: hidden;
  }

  .register-top {
    flex-direction: column;
  }

  .monies {
    align-items: center;
    justify-content: space-around;
  }
  #change-due {
    width: 45vw;
  }
}
<!--Psalms 37:21 The wicked borrow and do not repay, but the righteous give generously.-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>Cash Register</title>
    <link rel="stylesheet" href="styles.css"/>
  </head>
  <body>
    <div class="register-top">
      <div id="screen">
      </div>
      <div class="monies">
        <p>Price: <span id="price"></span></p>
        <label for="cash">Cash Paid: <input id="cash" type="number"/></label>
        <div id="change-due"></div>
      </div>
    </div>
    <button id="purchase-btn" type="button">Purchase</button>
    <script src="script.js"></script>
  </body>
</html>

Is this correct or is there something wrong with the code

You are failing the random tests, that means you may have some precision issues in your code

Add this below your code in the JS file

console.log("\nTest #19");
price = 44.42;
document.querySelector("#cash").value = 60;
cid =  [ [ 'PENNY', 0.88 ],
  [ 'NICKEL', 1.35 ],
  [ 'DIME', 2.6 ],
  [ 'QUARTER', 0.75 ],
  [ 'ONE', 0 ],
  [ 'FIVE', 0 ],
  [ 'TEN', 10 ],
  [ 'TWENTY', 0 ],
  [ 'ONE HUNDRED', 0 ] ];
document.querySelector("#purchase-btn").click();
console.log("actual", document.querySelector("#change-due").innerText);
console.log("expected", "Status: CLOSED TEN: $10 QUARTER: $0.75 DIME: $2.6 NICKEL: $1.35 PENNY: $0.88");

You will need to make it work

Oh thanks alot for the headsup

/*Psalms 37:21 The wicked borrow and do not repay, but the righteous give generously.*/
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]
];

const denominations = [
  ['PENNY', 0.01],
  ['NICKEL', 0.05],
  ['DIME', 0.1],
  ['QUARTER', 0.25],
  ['ONE', 1],
  ['FIVE', 5],
  ['TEN', 10],
  ['TWENTY', 20],
  ['ONE HUNDRED', 100]
]


const priceSpan = document.getElementById('price');
const cashPaid = document.getElementById('cash');
const changeDisplay = document.getElementById('change-due');
const screen = document.getElementById('screen');
const purchaseBtn = document.getElementById('purchase-btn');
let giveChange = false;
let hasRun = false;
priceSpan.innerText = `$${price}`;

let totalCid = Number(cid.reduce((acc, el) => el[1] + acc, 0)
                  .toFixed(2));

let balance = 0;

const stats = (bal, initTotalCid, initBal) => {
  totalCid = Number(cid.reduce((acc, el) => el[1] + acc, 0)
                  .toFixed(2));
  
  if((totalCid === 0 && bal === 0 && giveChange) || (totalCid === 0 && bal === 0 && giveChange && initBal === initTotalCid))
    return '<strong>Status</strong>: CLOSED<br/>';
  else if(bal == 0) 
    return '<strong>Status</strong>: OPEN<br/>';
  else if( bal > 0)
   return '<strong>Status</strong>: INSUFFICIENT_FUNDS';
  else 
    return;
   
}

const hasSuitableLowerDenominations = (bal, change) => {
  const changeArr = change.map((el) => [...el]);
  let internalBalance = bal;

  for (let i = (changeArr.length - 1); i >= 0; i--) {
    if (denominations[i][1] < internalBalance) {
      while (changeArr[i][1] > 0) {
        internalBalance = Number((internalBalance - denominations[i][1]).toFixed(2));
        changeArr[i][1] = Number((changeArr[i][1] - denominations[i][1]).toFixed(2));
      }
    }
    if (internalBalance <= 0) return true;
  }

  return false;
}

const check = (paid) => {
  balance = Number((paid - price).toFixed(2));
  if(paid < price) {
    alert('Customer does not have enough money to purchase the item');
    return;
  } else if(paid === price) {
    changeDisplay.innerHTML = 'No change due - customer paid with exact cash';
    return;
  }
  
  if(totalCid < balance || balance < 0 || hasSuitableLowerDenominations(balance, cid) == false)
    giveChange = false; 
  else if(totalCid === balance) 
    giveChange = true; 
  else if(totalCid > balance) 
    giveChange = true;
  
  balanceCalculator(paid);
}

const balanceCalculator = (paid) => {
  let index = cid.length - 1;
  let currentChange = cid.slice();
  const ogBalance = Number((paid - price).toFixed(2));
  const ogTotalCid = totalCid;
  hasRun = true;

  let denominationCount = {};
  while(balance > 0 && index >= 0 && giveChange) {
    while(balance >= denominations[index][1] && balance - denominations[index][1] >= 0 && currentChange[index][1] >= denominations[index][1] ) {
      balance = Number((balance - denominations[index][1]).toFixed(2));
      currentChange[index][1] = Number((currentChange[index][1] - denominations[index][1]).toFixed(2));
      if(denominationCount[denominations[index][0]])
        denominationCount[denominations[index][0]] ++;
      else
        denominationCount[denominations[index][0]] = 1;
    }
    if(index > 0)
      index--;

  }

  cid = currentChange;
  totalCid = Number(cid.reduce((acc, el) => el[1] + acc, 0)
                  .toFixed(2));
  updateUI(denominationCount, ogTotalCid, ogBalance);
}

const updateUI = (obj, originalTotalCid, originalBalance) => {
  changeDisplay.innerHTML = '';
  screen.innerHTML = '';

  if(hasRun) {
    changeDisplay.innerHTML = stats(balance, originalTotalCid, originalBalance);
  }
  if(obj && giveChange)
    Object.keys(obj).forEach((key)=> {
      let value;
      denominations.forEach((item, index) => {
        if(key === item[0]) {
          value = denominations[index][1];
          return;
        }
      })

      changeDisplay.innerHTML +=  `${key}: $${Number((value * obj[key]).toFixed(2))} `;
    })


  cid.forEach((el)=> {
    const coinDiv = document.createElement('div');
    coinDiv.innerHTML = `<strong>${el[0]}</strong> : $${el[1]}`;
    screen.append(coinDiv);
  })
  const totalDiv = document.createElement('div');
  totalDiv.innerHTML = `<strong>TOTAL</strong>: $${totalCid}`;
  screen.append(totalDiv);
}

updateUI();

purchaseBtn.addEventListener('click', () => {
  check(Number(cashPaid.value));
})

cashPaid.addEventListener('keydown', (e) => {
  if(e.key === 'Enter')
    check(Number(cashPaid.value));
})

console.log("\nTest #19");
price = 44.42;
document.querySelector("#cash").value = 60;
cid =  [ [ 'PENNY', 0.88 ],
  [ 'NICKEL', 1.35 ],
  [ 'DIME', 2.6 ],
  [ 'QUARTER', 0.75 ],
  [ 'ONE', 0 ],
  [ 'FIVE', 0 ],
  [ 'TEN', 10 ],
  [ 'TWENTY', 0 ],
  [ 'ONE HUNDRED', 0 ] ];
document.querySelector("#purchase-btn").click();
console.log("actual", document.querySelector("#change-due").innerText);
console.log("expected", "Status: CLOSED TEN: $10 QUARTER: $0.75 DIME: $2.6 NICKEL: $1.35 PENNY: $0.88");

it seems to pass or is the problem formatting

Also I notice the js code I sent before was an earlier version since the one I had corrected was not saved

you seem to have some issues with global variables

add this below the code you already have, do not delete the other test

console.log("\nTest #19v2");
price = 40.7;
document.querySelector("#cash").value = 70;
cid =  [ [ 'PENNY', 0.05 ],
  [ 'NICKEL', 0.35 ],
  [ 'DIME', 0.4 ],
  [ 'QUARTER', 3.5 ],
  [ 'ONE', 0 ],
  [ 'FIVE', 5 ],
  [ 'TEN', 20 ],
  [ 'TWENTY', 0 ],
  [ 'ONE HUNDRED', 0 ] ];
document.querySelector("#purchase-btn").click();
console.log("actual", document.querySelector("#change-due").innerText);
console.log("expected", "Status: CLOSED TEN: $20 FIVE: $5 QUARTER: $3.5 DIME: 0.4 NICKEL: $0.35 PENNY: $0.05");

and then try to remove the other one, notice how the actual value changes

I think I will have to go through the whole implementation and check for places where the global variable states are being interfered with. I think I will also redo the denominations function. I will get back to you with my progress.

Hey ILM, thanks for your help. I could not have done this without you pointing me in the right direction. God bless you abundantly and I hope to interact more in the future. Here is the final code:

removed by mod

Glad you got it, please do not post solution code to the forum :+1:

Oh noted, appologies I was just very excited :sweat_smile: