Calculation function dead end

Thanks Russell, you’ve probably worked out how thick I am with this stuff lol (it took 5 mins in Excel)
I have added that in but still shows 0 commission.
Where was the minu function and I will put that back in to see if it helps.

Don’t be hard on yourself, a bit of a break will probably do the trick:)

There is an issue with the commission by the looks of it, so it does need addressing.

It daft o’clock here now, so that’s me done for tonight.

Will have a butchers tomorrow.

1 Like

On which one of the several listed above have you done that?

Hi Paul that’s on the salonlogic.co.uk/forms/Commission/Commission.php one. It’s the one I’d like to get working the others are fallbacks. Sorry for the confusion. :slight_smile:

I added a console.log statement to the commission if statement, and with inputs of 40 hours, 3.75 rate, 3.5 multiplier, and 900 takings, the commission ends up calculated to be -5, and set to zero.

Paul thanks, that sounds right how do I sort that please?

Can you please give details about what is supposed to happen instead.

1 Like

A first run up at this exercise, without formCalc. Re-factoring needed.

Edit: Amended to get the output and input fields dynamically

<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>Payroll</title>
  <link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css'>
  <style>
    input[type=number]::-webkit-inner-spin-button,
    input[type=number]::-webkit-outer-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }

    .payroll-container{
      max-width: 800px;
    }
  </style>
</head>
<body>
<main class='container'>
  <div class='payroll-container row p-3'>
    <h4 class='mb-3'>Payroll and Commission Calculator</h4>
    <form id='payrollForm' class='payroll-form' name='payrollForm'>
      <div class='form-group row'>
        <label for='hours-worked' class='col-sm-6 col-form-label'>Hours Worked</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='hoursWorked' placeholder='0' tabindex='1'>
        </div>
      </div>
      <!-- rate per hour and base pay total -->
      <div class='form-group row'>
        <label for='hourly-rate' class='col-sm-6 col-form-label'>Rate per hour</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='hourlyRate' placeholder='0.00' tabindex='2'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='basePay' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- target multiplier and target total -->
      <div class='form-group row'>
        <label for='target-multiplier' class='col-sm-6 col-form-label'>Target Multiplier</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='targetMultiplier' placeholder='0.00' tabindex='3'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='target' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- actual weekly takings and net pay -->
      <div class='form-group row'>
        <label for='weekly-takings' class='col-sm-6 col-form-label'>Gross Weekly takings</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='weeklyTakings' placeholder='0.00' tabindex='4'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='netEarnings' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
    </form>
  </div>
</main>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src='https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js'></script>
<script>
const VAT = 1.2

const getElem = function(selector, root = document) {
  return root.querySelector(selector)
}

const getElems = function(selector, root = document) {
  return root.querySelectorAll(selector)
}

const toCurrency = function(value, currency = '£') {
  return `${currency}${value.toFixed(2)}`
}

const toValue = function(strg, currency = '£') {
  return (!isNaN(strg)) ? strg : Number(strg.replace(currency, '')) || 0
}

const getFieldsById = function(elems) {
  return Array.from(elems).reduce(function(target, elem){
    target[elem.id] = elem
    return target
  }, {})
}

const form = getElem('#payrollForm')

const formOutputs = getFieldsById(getElems('input:read-only', form))

const formInputs = getFieldsById(getElems('input:not(:read-only)', form))

const calculate = {
  basePay: function({hoursWorked, hourlyRate}) {
    return toValue(hoursWorked) * toValue(hourlyRate)
  },
  target: function({basePay, targetMultiplier}) {
    return toValue(basePay) * toValue(targetMultiplier) * VAT
  },
  netEarnings: function({weeklyTakings}) {
    return toValue(weeklyTakings) / VAT
  }
}

const getFieldValues = function(fields) {
  const result = {}

  for (let fieldName in fields) {
    result[fieldName] = fields[fieldName].value
  }
  return result
}

const updateOutputs = function ( inputs, outputs ) {
  const result = {}
  const allFields = getFieldValues(Object.assign(inputs, outputs))

  for (let field in allFields ) {
    if (outputs[field]) {
      result[field] = calculate[field](allFields)
    }
  }
  return result
}

const renderOutputs = function (newFigures) {
  for (let output in formOutputs ) {
    formOutputs[output].value = toCurrency(newFigures[output])
  }
}

const handler = function(event) {
  const elem = event.target

  if (formInputs[elem.id]) {
    renderOutputs(updateOutputs(formInputs, formOutputs))
  }
}

form.addEventListener('keyup', handler, false)

</script>
</body>
</html>

As Paul has asked what is supposed to happen with commission?

1 Like

This has turned into a bit of a personal project (by the looks of it). The code needs a good sort out, but this is it for now.

<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>Payroll</title>
  <link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css'>
  <style>
    input[type=number]::-webkit-inner-spin-button,
    input[type=number]::-webkit-outer-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }

    .payroll-container{
      max-width: 800px;
    }
  </style>
</head>
<body>
<main class='container'>
  <div class='payroll-container row p-3'>
    <h4 class='mb-3'>Payroll and Commission Calculator</h4>
    <form id='payrollForm' class='payroll-form' name='payrollForm'>
      <div class='form-group row'>
        <label for='hours-worked' class='col-sm-6 col-form-label'>Hours Worked</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='hoursWorked' placeholder='0' tabindex='1'>
        </div>
      </div>
      <!-- rate per hour and base pay total -->
      <div class='form-group row'>
        <label for='hourly-rate' class='col-sm-6 col-form-label'>Rate per hour</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='hourlyRate' placeholder='0.00' tabindex='2'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='basePay' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- target multiplier and target total -->
      <div class='form-group row'>
        <label for='target-multiplier' class='col-sm-6 col-form-label'>Target Multiplier</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='targetMultiplier' placeholder='0.00' tabindex='3'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='target' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- actual weekly takings and net pay -->
      <div class='form-group row'>
        <label for='weekly-takings' class='col-sm-6 col-form-label'>Gross Weekly takings</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='weeklyTakings' placeholder='0.00' tabindex='4'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='netEarnings' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- wage -->
      <div class='form-group row'>
        <label for='wage' class='col-sm-9 col-form-label'>Wage</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='wage' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- holiday pay accrued -->
      <div class='form-group row'>
        <label for='holidayPayAccrued' class='col-sm-9 col-form-label'>Holiday Pay Accrued</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='holidayPayAccrued' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- pension contribution -->
      <div class='form-group row'>
        <label for='pensionContribution' class='col-sm-6 col-form-label'>Pension Contribution%</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='pensionContribution' placeholder='0' tabindex='5'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='pension' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- national insurance contribution -->
      <div class='form-group row'>
        <label for='nationalInsurance' class='col-sm-9 col-form-label'>N.I. Contribution</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='nationalInsurance' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- total payroll cost -->
      <div class='form-group row'>
        <label for='total' class='col-sm-9 col-form-label'>Total Payroll Cost</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' class='form-control' id='total' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
    </form>
  </div>
</main>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src='https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js'></script>
<script>
const vatPercent = 1.2
const nationalInsurancePercent = 13.8

const getElem = function(selector, root = document) {
  return root.querySelector(selector)
}

const getElems = function(selector, root = document) {
  return root.querySelectorAll(selector)
}

const toCurrency = function(value, currency = '£') {
  return `${currency}${Number(value).toFixed(2)}`
}

const toValue = function(value, currency = '£') {
  return (typeof value === 'string') ? Number(value.replace(currency, '')) : Number(value || 0)
}

const percentOf = function(from, percent) {
  return percent / 100 * from
}

const getFieldsById = function(elems) {
  return Array.from(elems).reduce(function(target, elem){
    target[elem.id] = elem
    return target
  }, {})
}

const form = getElem('#payrollForm')

const formOutputs = getFieldsById(getElems('input:read-only', form))

const formInputs = getFieldsById(getElems('input:not(:read-only)', form))

const calculate = {
  basePay({hoursWorked, hourlyRate}) {
    return toValue(hoursWorked) * toValue(hourlyRate)
  },
  target({basePay, targetMultiplier}) {
    return toValue(basePay) * toValue(targetMultiplier) * vatPercent
  },
  netEarnings({weeklyTakings}) {
    return toValue(weeklyTakings) / vatPercent
  },
  wage({basePay, commission}) {
    return toValue(basePay) + toValue(commission)
  },
  holidayPayAccrued({hoursWorked, hourlyRate}) {
    return 12.07 / 100 * toValue(hoursWorked) * toValue(hourlyRate)
  },
  pension({wage, pensionContribution}) {
    return percentOf(toValue(wage), toValue(pensionContribution))
  },
  nationalInsurance({wage, nationalInsuranceContribution}) {
    return percentOf(toValue(wage), nationalInsurancePercent)
  },
  total({wage, holidayPayAccrued, pensionContribution, nationalInsurance}) {
    return [wage, holidayPayAccrued, pensionContribution, nationalInsurance].reduce(
      function(acc, val) { return toValue(acc) + toValue(val) }
    )
  }
}

const getFieldValues = function(fields) {
  const result = {}

  for (let fieldName in fields) {
    result[fieldName] = fields[fieldName].value
  }
  return result
}

const updateOutputs = function ( inputs, outputs ) {
  const result = {}
  const allFields = getFieldValues(Object.assign(inputs, outputs))

  for (let field in allFields ) {
    if (outputs[field]) {
      result[field] = calculate[field](allFields)
    }
  }
  return result
}

const renderOutputs = function (newFigures, formOutputs) {

  for (let output in formOutputs ) {
    formOutputs[output].value = toCurrency(newFigures[output])
  }
}

const handler = function(event) {
  const elem = event.target

  if (formInputs[elem.id]) {
    renderOutputs(updateOutputs(formInputs, formOutputs), formOutputs)
  }
}

form.addEventListener('keyup', handler, false)
</script>
</body>
</html>
1 Like

Russell, that is amazing thankyou so so much. I really appreciate the time you have given me here.
I think the form builder was never going to let me learn how to do this properly but more so that every time something changed I would be back picking yourself and Pauls brains.

The commission calculation would be;

Upto 3.5 times wage hourly rate (base pay) so £630 less vat = £525 is base pay
Actual Gross takings £900 less vat = 750
So a % commission would be paid on 750-525 so commission on figure would be £225

I’m confused about the VAT.

Using the sample values that you’ve given before, what I’m seeing on the form is that 40 * 3.75 gives a weekly pay rate of 150. And, that 3.5 (target) times that gives a weekly target of 525.

It seems that VAT is not involved with any of those calculations, so I’m confused about why you’ve introduced the idea of subtracting VAT.

Is it your understanding that some of the figures on the form include VAT, and some don’t include it?

Hi Paul, the target figure was always £630 which included vat but had a hidden calculation to remove it.
The actual gross was the same although that function was just Actual Gross/1,2. :slight_smile:
You have alerted me to something I hadn’t considered though which is if a salon is not VAT registered.
Might need to have two calculators one with vat and one without.

Using those sample figures that you presented earlier (40, 3.75, 3.5) in post #24, can you please take me through the needed calculations to get to 630?

Hi Paul, sorry the calculation is 40x3.75 = 150x 3.5 = 525 but the answer in the original calculator showed 630 as the target which was (150x3.5)x1.2. :slight_smile:

What do you think that the form should do? Should it ignore VAT as it currently seems to do, or should VAT be included in some of the figures?

I recommend that when changes from without VAT to with VAT occur, that those are explicitly calculated and shown on the form too, similar to when filling out tax forms.

That helps to prevent confusions that have just been demonstrated here.

Thanks Paul, I hadn’t thought of that, its probably a better idea to do it the way you are suggesting. :slight_smile:

1 Like

An update to the code from yesterday. I haven’t included the new calculations yet, but have fixed some issues

I have added a dataset property to each of the inputs now called data-calc. This property corresponds with the function/methods that need to be called on those inputs basePay, netEarnings etc. I previously used the id names for this, but think it’s best to keep that separate.

The output fields I have changed to a mapped array as opposed to an object, that way we can guarantee that the fields are calculated top to bottom in order.

The updateOutputs had an issue where it wasn’t working with the updated figures being generated in the loop, which is now fixed.

It’s in a bit better shape anyway:)

Full code

<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>Payroll</title>
  <link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css'>
  <style>
    input[type=number]::-webkit-inner-spin-button,
    input[type=number]::-webkit-outer-spin-button {
      -webkit-appearance: none;
      margin: 0;
    }

    .payroll-container{
      max-width: 800px;
    }
  </style>
</head>
<body>
<main class='container'>
  <div class='payroll-container row p-3'>
    <h4 class='mb-3'>Payroll and Commission Calculator</h4>
    <form id='payroll-form' class='payroll-form' name='payroll-form'>
      <div class='form-group row'>
        <label for='hours-worked' class='col-sm-6 col-form-label'>Hours Worked</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' class='form-control' id='hours-worked' data-calc='hoursWorked' placeholder='0' tabindex='1'>
        </div>
      </div>
      <!-- rate per hour and base pay total -->
      <div class='form-group row'>
        <label for='hourly-rate' class='col-sm-6 col-form-label'>Rate per hour</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' id='hourly-rate' class='form-control' data-calc='hourlyRate' placeholder='0.00' tabindex='2'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='base-pay' class='form-control form-output' data-calc='basePay' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- target multiplier and target total -->
      <div class='form-group row'>
        <label for='target-multiplier' class='col-sm-6 col-form-label'>Target Multiplier</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' id='target-multiplier' class='form-control' data-calc='targetMulti' placeholder='0.00' tabindex='3'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='target' class='form-control form-output' data-calc='target' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- actual weekly takings and net pay -->
      <div class='form-group row'>
        <label for='weekly-takings' class='col-sm-6 col-form-label'>Gross Weekly takings</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' id='weekly-takings' class='form-control' data-calc='weeklyTakings' placeholder='0.00' tabindex='4'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='net-earnings' class='form-control form-output' data-calc='netEarnings' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- wage -->
      <div class='form-group row'>
        <label for='wage' class='col-sm-9 col-form-label'>Wage</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='wage' class='form-control form-output' data-calc='wage' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- holiday pay accrued -->
      <div class='form-group row'>
        <label for='holiday-pay' class='col-sm-9 col-form-label'>Holiday Pay Accrued</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='holiday-pay' class='form-control form-output' data-calc='holidayPay' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- pension contribution -->
      <div class='form-group row'>
        <label for='pension-contribution' class='col-sm-6 col-form-label'>Pension Contribution %</label>
        <div class='col-sm-3 mb-2'>
          <input type='number' id='pension-contribution' class='form-control' data-calc='pensionContrib' placeholder='0' min='0' max='100' tabindex='5'>
        </div>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='pension' class='form-control form-output' data-calc='pension' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- national insurance contribution -->
      <div class='form-group row'>
        <label for='national-insurance' class='col-sm-9 col-form-label'>N.I. Contribution</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='national-insurance' class='form-control form-output' data-calc='nationalInsurance' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
      <!-- total payroll cost -->
      <div class='form-group row'>
        <label for='total' class='col-sm-9 col-form-label'>Total Payroll Cost</label>
        <div class='col-sm-3 mb-2'>
          <input type='text' id='total' class='form-control form-output' data-calc='total' value='£0.00' readonly tabindex='-1'>
        </div>
      </div>
    </form>
  </div>
</main>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src='https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js'></script>
<script>
const getElem = function (selector, root = document) {
  return root.querySelector(selector)
}

const getElems = function (selector, root = document) {
  return root.querySelectorAll(selector)
}

const toPounds = function (val) {
  if (Number.isFinite(val)) return `£${val.toFixed(2)}`
}

const toVal = function (val) {
  return (typeof val === 'string') ? Number(val.replace('£', '')) : Number(val)
}

const percentOf = function (from, percent) {
  return percent / 100 * from
}

const mapToArray = function (inputs, fn, key = 'calc') {
  const fields = Array.from(inputs)

  return fields.map(function (field) {
    return [field.dataset[key], (typeof fn === 'function') ? fn(field) : field]
  })
}

const mapToObject = function (inputs, fn, key = 'calc') {
  const fields = Array.from(inputs)

  return fields.reduce(function (obj, field) {
    obj[field.dataset[key]] = (typeof fn === 'function') ? fn(field) : field
    return obj
  }, {})
}

const vat = 1.2
const natInsurance = 13.8

const calculate = {
  basePay: function ({ hoursWorked, hourlyRate }) {
    return toVal(hoursWorked) * toVal(hourlyRate)
  },

  target: function ({ basePay, targetMulti }) {
    return toVal(basePay) * toVal(targetMulti) * vat
  },

  netEarnings: function ({ weeklyTakings }) {
    return toVal(weeklyTakings) / vat
  },

  wage: function ({ basePay/*,  commission */ }) {
    return toVal(basePay) /* + toVal(commission) */
  },

  holidayPay: function ({ hoursWorked, hourlyRate }) {
    return 12.07 / 100 * toVal(hoursWorked) * toVal(hourlyRate)
  },

  pension: function ({ wage, pensionContrib }) {
    return percentOf(toVal(wage), toVal(pensionContrib))
  },

  nationalInsurance: function ({ wage }) {
    return percentOf(toVal(wage), natInsurance)
  },

  total: function ({ wage, holidayPay, pension, nationalInsurance }) {
    return toVal(wage) + toVal(holidayPay) + toVal(pension) + toVal(nationalInsurance)
  }
}

const updateOutputs = function (outputFields, allFields) {
  const currFields = Object.assign({}, allFields)
  const outputs = {}

  for (const [name, field] of outputFields) {
    outputs[name] = (currFields[name] = calculate[name](currFields))
  }
  return outputs
}

const renderOutputs = function (outputFields, newFigures) {
  for (const [name, field] of outputFields) {
    field.value = toPounds(newFigures[name])
  }
}

const form = getElem('#payroll-form')
const allFields = getElems('input', form)
const outputFields = mapToArray(getElems('.form-output', form))

const formUpdate = function (event) {
  const elem = event.target

  if (elem.nodeName && elem.nodeName === 'INPUT') {
    const updatedFigures = updateOutputs(outputFields, mapToObject(
      allFields, function (field) { return field.value })
    )
    renderOutputs(outputFields, updatedFigures)
  }
}

form.addEventListener('keyup', formUpdate, false)
</script>
</body>
</html>

javascript

const getElem = function (selector, root = document) {
  return root.querySelector(selector)
}

const getElems = function (selector, root = document) {
  return root.querySelectorAll(selector)
}

const toPounds = function (val) {
  if (Number.isFinite(val)) return `£${val.toFixed(2)}`
}

const toVal = function (val) {
  return (typeof val === 'string') ? Number(val.replace('£', '')) : Number(val)
}

const percentOf = function (from, percent) {
  return percent / 100 * from
}

const mapToArray = function (inputs, fn, key = 'calc') {
  const fields = Array.from(inputs)

  return fields.map(function (field) {
    return [field.dataset[key], (typeof fn === 'function') ? fn(field) : field]
  })
}

const mapToObject = function (inputs, fn, key = 'calc') {
  const fields = Array.from(inputs)

  return fields.reduce(function (obj, field) {
    obj[field.dataset[key]] = (typeof fn === 'function') ? fn(field) : field
    return obj
  }, {})
}

const vat = 1.2
const natInsurance = 13.8

const calculate = {
  basePay: function ({ hoursWorked, hourlyRate }) {
    return toVal(hoursWorked) * toVal(hourlyRate)
  },

  target: function ({ basePay, targetMulti }) {
    return toVal(basePay) * toVal(targetMulti) * vat
  },

  netEarnings: function ({ weeklyTakings }) {
    return toVal(weeklyTakings) / vat
  },

  wage: function ({ basePay/*,  commission */ }) {
    return toVal(basePay) /* + toVal(commission) */
  },

  holidayPay: function ({ hoursWorked, hourlyRate }) {
    return 12.07 / 100 * toVal(hoursWorked) * toVal(hourlyRate)
  },

  pension: function ({ wage, pensionContrib }) {
    return percentOf(toVal(wage), toVal(pensionContrib))
  },

  nationalInsurance: function ({ wage }) {
    return percentOf(toVal(wage), natInsurance)
  },

  total: function ({ wage, holidayPay, pension, nationalInsurance }) {
    return toVal(wage) + toVal(holidayPay) + toVal(pension) + toVal(nationalInsurance)
  }
}

const updateOutputs = function (outputFields, allFields) {
  const currFields = Object.assign({}, allFields)
  const outputs = {}

  for (const [name, field] of outputFields) {
    outputs[name] = (currFields[name] = calculate[name](currFields))
  }
  return outputs
}

const renderOutputs = function (outputFields, newFigures) {
  for (const [name, field] of outputFields) {
    field.value = toPounds(newFigures[name])
  }
}

const form = getElem('#payroll-form')
const allFields = getElems('input', form)
const outputFields = mapToArray(getElems('.form-output', form))

const formUpdate = function (event) {
  const elem = event.target

  if (elem.nodeName && elem.nodeName === 'INPUT') {
    const updatedFigures = updateOutputs(outputFields, mapToObject(
      allFields, function (field) { return field.value })
    )
    renderOutputs(outputFields, updatedFigures)
  }
}

form.addEventListener('keyup', formUpdate, false)

1 Like

Thanks Russell I really appreciate the time you have given me.

No worries Scotty, it’s a pretty good exercise:)

I’m sure it could be done more elegantly, I have had fp programming in the back of my mind. If anyone spots any howlers, or major flaws, it would be appreciated.