Client Script Function Error

I’m trying to calculate total amount using client script function. However, some of the caluclations return wrong values or do not refresh unless triggered multiple times:

I have different discount bands depending on total days:

Band A: Above 7 days = discount is 31,500
Band B: Above 30 days = discount is 29,750
Band C: Above 90 days = discount is 28,000
Band D: Above 365 days - discount is 26,250

If total days = Band A, calculation is correct
If total days is however greater than Band A, initial result returned is wrong. I have to trigger change of total_days multiple times before calculation recognises the changes in the new band. And sometimes the calculation returns with fractional errors. I have been trying to figure out where by script is wrong but can’t find it. Any help will be appreciated. Below is my script.

total_days: function(frm) {
        var a = (frm.doc.total_days * frm.doc.rate) + frm.doc.caution_fee;
        var b = (frm.doc.total_days * frm.doc.discount_amount) + frm.doc.caution_fee;
        var c = ((frm.doc.total_days * frm.doc.discount_amount) * 0.10);
        
        if (frm.doc.total_days * frm.doc.discount_amount < 1000000) {
          frm.set_value("caution_fee", 60000);
          
            
        }
        
        if (frm.doc.total_days * frm.doc.discount_amount > 999999) {
          frm.set_value("caution_fee", c);
            
        }
        
        if (frm.doc.total_days < 7) {
          frm.set_value("total_amount", a);
          frm.set_value("total_received", a);
            
        }
        
        if (frm.doc.total_days > 6 && frm.doc.total_days < 31) {
          frm.set_value("discount_amount", 31500);
          frm.refresh_field("discount_amount");
          frm.set_value("total_amount", b);
          frm.set_value("total_received", b);
         
        }
        
        if (frm.doc.total_days > 30 && frm.doc.total_days < 91) {
          frm.set_value("discount_amount", 29750);
          frm.refresh_field("discount_amount");
          frm.set_value("total_amount", b);
          frm.set_value("total_received", b);
            
        }
        
        else if (frm.doc.total_days > 90 && frm.doc.total_days < 366) {
          frm.set_value("discount_amount", 28000);
          frm.set_value("total_amount", b);
          frm.set_value("total_received", b);
            
        }
        
        else if (frm.doc.total_days > 365) {
          frm.set_value("discount_amount", 26250);
          frm.set_value("total_amount", b);
          frm.set_value("total_received", b);
            
        }
        frm.refresh_field("discount_amount")
        frm.refresh_field("caution_fee")
        frm.refresh_field("total_amount");
        frm.refresh_field("total_received");
        
    },



Personally, I would pass all values to a pure JavaScript function, unit test somewhere apart, then fill the fields from the return value object in a separate operation.

const { total_days, rate, caution_fee, discount_amount } = frm.doc;
const parms = { total_days, rate, caution_fee, discount_amount };
const { discount_amount, caution_fee, total_amount, total_received } = pureJS(parms);

frm.set_value("discount_amount", discount_amount)
frm.refresh_field("discount_amount")

etc
1 Like

@MartinHBramwell Thanks for the suggestion. Unfortunately, I am not really a developer and I have very limited knowledge of javascript so it may be difficult for me to write the script as you suggested. But any guide I can get to do this will be appreciated as it will be one more piece of knowledge gained for me :grinning:.

But just to ask, does that mean converting it to a backend server script? As I am unaware one can run anything other than pure (but limited) python script from the client script or the frontend server script.

If you paste the code below into an html file, named something like …

flexy2ky.html

… then drag it into a browser, you should have everything you need in order to correct your discount rules.

Most browsers have a Web Developer tool that allows you to see error messages and all results of commands like console.log(`partial result = ${rslt}`)

<!DOCTYPE html>
<html>
<body>

<h2>JavaScript Functions</h2>

<form onsubmit="return false;" method="post" name="myForm">
  <label for="total_days">Total Days:</label>
  <input type="text" id="total_days" value="44" name="total_days"><br>

  <label for="rate">Rate:</label>
  <input type="text" id="rate" value="5" name="rate"><br>

  <label for="caution_fee">Caution Fee:</label>
  <input type="text" id="caution_fee" value="6" name="caution_fee"><br>

  <label for="discount_amount">Discount Amount:</label>
  <input type="text" id="discount_amount" value="7" name="discount_amount"><br>

  <input type="submit" name="submit" onclick="test()" value="Test" />


</form>

Discount Amount <p id="da"></p>
Caution Fee <p id="cf"></p>
Total Amount <p id="ta"></p>
Total Rec'd<p id="tr"></p>

<script>

const pureJS = parms => {

  const { total_days, rate, caution_fee, discount_amount } = parms;

  let discountAmount = 0;
  let cautionFee = 0;
  let totalAmount = 0;
  let totalReceived = 0;

  var a = (total_days * rate) + caution_fee;
  var b = (total_days * discount_amount) + caution_fee;
  var c = ((total_days * discount_amount) * 0.10);

  console.log(`a= ${a}`)
  console.log(`b= ${b}`)
  console.log(`c= ${c}`)

  if (total_days * discount_amount < 1000000) {
    cautionFee = 60000
  }

  if (total_days * discount_amount > 999999) {
    cautionFee = 60000
  }

  if (total_days < 7) {
    totalAmount = a;
    totalReceived = a;
  } else {
    totalAmount = b;
    totalReceived = b;
  }

  if (total_days > 6 && total_days < 31) {
    discountAmount = 31500;
  } else if (total_days > 30 && total_days < 91) {
    discountAmount = 29750;
  } else if (total_days > 90 && total_days < 366) {
    discountAmount = 28000;
  } else if (total_days > 365) {
    discountAmount = 26250;
  }

  return { discountAmount, cautionFee, totalAmount, totalReceived };
}

function totalDays(frm) {
  const { total_days, rate, caution_fee, discount_amount } = frm.doc;
  const parms = {
    total_days: parseInt(total_days, 10),
    rate: parseInt(rate, 10),
    caution_fee: parseInt(caution_fee, 10),
    discount_amount: parseInt(discount_amount, 10)
  };
  return pureJS(parms);
}

function test() {

  const frm = { doc: {
    total_days: 0,
    rate: 0,
    caution_fee: 0,
    discount_amount: 0
  }}

  frm.doc.total_days = document.getElementById("total_days").value;
  frm.doc.rate = document.getElementById("rate").value;
  frm.doc.caution_fee = document.getElementById("caution_fee").value;
  frm.doc.discount_amount = document.getElementById("discount_amount").value;

  const { discountAmount, cautionFee, totalAmount, totalReceived } = totalDays(frm);
  document.getElementById("da").innerHTML = discountAmount;
  document.getElementById("cf").innerHTML = cautionFee;
  document.getElementById("ta").innerHTML = totalAmount;
  document.getElementById("tr").innerHTML = totalReceived;

}

</script>

</body>
</html>

@MartinHBramwell Thanks a bunch for this. I tested using the script above and my results were accurate without making any changes to my underlying code. However, the code still returns incorrect values from Band B and above (which is the first problem) and does not calculate correctly on the first try if I select the first day of a higher band on the first try (which is the second problem) and sometimes the calculation is off by a fraction. This only happens when I apply the code to my custom doctype and I can’t seem to figure out why it behaves differently when applied to the doctype.

One thing I noticed is that you have given the same name to a function and to a variable:

total_days: function(frm) {
  

and

frm.doc.total_days

This could very likely drive the whole thing into cuckoo-land.

If you look at my code I avoid ambiguity by using different nomenclature:

total_days

versus

totalDays