Search code examples
javascriptjqueryjquery-calculation

Calculate total subsciption fee based on changing subscription fees


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


Solution

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