0

Im trying to calculate the total subscription fee for the penalty jar at my workplace. Every month everyone pays a certain fee on top of their penalties. It started out being 20DKK and now it's 25DKK. I have the tdata in two json objects - one with persons and one with the subscription fees

It looks like this:

subscriptionFees = [
   {
      "id":2,
      "date":"1900-01-01T00:00:00",
      "amount":20.0
   },
   {
      "id":1,
      "date":"2018-05-01T00:00:00",
      "amount":25.0
   }
]
persons = [
   {
      "id":11,
      "name":"Camilla",
      "active":true,
      "startDate":"2017-01-01",
      "endDate":"1900-01-01"
   },
   {     
      "id":6,
      "name":"Cathrine",
      "active":true,
      "startDate":"2019-03-01",
      "endDate":"1900-01-01"
   },
   {     
      "id":1,
      "name":"John",
      "active":true,
      "startDate":"2020-03-01",
      "endDate":"2021-03-01"
   }
]

I'm using jquery for most of my js functions. I imagine a function running through the persons-object and calculating the total subscription fee for each of them.

Maybe something like this:

 $.each(persons, function (id, obj) {
    totalSubscriptionfee = calculateSubscriptionfee(obj.startDate, obj.endDate);

 })


 function calculateSubscriptionfee(startDate, endDate){
     
    ???

 }

Can someone help me with the calculateSubscriptionfee-function? The subscription fee might get changed again in the future, so the function needs to be able to adjust for that.

Thanks,

Peter

  • is this right: `"startDate":"2017-01-01", "endDate":"1900-01-01"` - seems backwards? – Kinglish Jun 10 '21 at 17:29
  • Do you want the total due or just the monthly amount per person? – Kinglish Jun 10 '21 at 17:39
  • Hi Kinglish - it's instead of having a null value for the members that are still active and in looking to having the total membership fee due from when they started until they stopped or from when they started and until now. Only whole months count – Peter Andreas Rothe Jun 11 '21 at 09:36

1 Answers1

0

I may have made this too complicated, but wasn't sure how else to approach it. This will

  • first create a ranges array with start, end and amount using reduce
  • map the persons array, iterating through ranges to get the amount due from that range (if any)
  • get the total duration, in milliseconds, convert to a rough approximation of number of months, then round down using a modulus.

In the end you get a new persons array (npersons) with the total due in it.

const subscriptionFees = [{
    "id": 2,
    "date": "1900-01-01T00:00:00",
    "amount": 20.0
  },
  {
    "id": 1,
    "date": "2018-05-01T00:00:00",
    "amount": 25.0
  }
]
const persons = [{
    "id": 11,
    "name": "Camilla",
    "active": true,
    "startDate": "2017-01-01",
    "endDate": "1900-01-01"
  },
  {
    "id": 6,
    "name": "Cathrine",
    "active": true,
    "startDate": "2019-03-01",
    "endDate": "1900-01-01"
  },
  {
    "id": 1,
    "name": "John",
    "active": true,
    "startDate": "2020-03-01",
    "endDate": "2021-03-01"
  }
]

let ranges = subscriptionFees.reduce((acc, a) => {
  if (acc.length === 0 || Object.hasOwnProperty(acc[acc.length - 1].end)) {
    let tmp = {
      start: a.date,
      amount: a.amount
    };
    acc.push(tmp)
  } else {
    acc[acc.length - 1].end = a.date;
    acc.push({
      start: a.date,
      amount: a.amount
    })
  }
  return acc;
}, [])

ranges[ranges.length - 1].end = new Date();

//console.log('ranges', ranges);

const npersons = persons.map(person => {
  let ttl = 0;
  // fix endDate
  if (new Date(person.endDate).getTime() < new Date(person.startDate).getTime()) person.endDate = new Date();

// iterate ranges
  ranges.forEach(a => {
    let end = Math.min(new Date(a.end).getTime(), new Date(person.endDate).getTime())

    let start = Math.max(new Date(a.start).getTime(), new Date(person.startDate).getTime())
    // console.log('calculating', person.name, 'start', new Date(start), 'end', new Date(end));

    let interval = end - start;
    if (interval > 0){
      let tmpttl = Math.floor( (interval / 1000 / 60 / 60 / 24 / 30) * +a.amount)
      tmpttl -= tmpttl % a.amount
      ttl += tmpttl;
      }

  })
  person.total = ttl
  return person

})

console.log(persons)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Kinglish
  • 23,358
  • 3
  • 22
  • 43