> For the complete documentation index, see [llms.txt](https://docs.agilecase.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.agilecase.com/developer-documentation/case-scripting/calculated-fields/banding-a-calculated-amount.md).

# Banding a Calculated Amount

Tiered arithmetic in a calculated field, and stripping currency before converting.

Levies, duties and banded fees all have the same shape: a threshold, a percentage above it, sometimes a flat addition. A calculated field is the natural home for one, because the result usually has to appear on a quote or an invoice as well as on screen.

## The scenario

An insurer charges an administrative levy on claims. Claims declared at £40,000 or more attract 3% plus a £60 fixed charge; anything below that is free.

| Setting          | Value                                   |
| ---------------- | --------------------------------------- |
| Calculated field | `6303` Claim levy                       |
| Source field     | `6304` Declared claim amount (currency) |

## The script

```javascript
function calc() {
    var amount = Service.CustomField(6304).ValueAsText
        .replace("£", "")
        .replace(/,/g, "");

    var declared = parseFloat(amount);

    if (isNaN(declared)) {
        return String((0).toFixed(2));
    }

    if (declared >= 40000) {
        return String(((declared * 0.03) + 60).toFixed(2));
    }

    return String((0).toFixed(2));
}
```

## Cleaning the value before converting

A currency field's value arrives formatted for display, so `£45,000.00` is what the script sees. `parseFloat` reads that as `NaN`, because it stops at the first character it cannot use and `£` is the first character there.

Stripping the symbol and the separators first is what makes the conversion work. Note the regular expression on the separator: `replace(",", "")` removes only the first comma, so a seven-figure amount such as `£1,250,000` would keep its second one and `parseFloat` would read it as `1250`. `replace(/,/g, "")` removes them all.

{% hint style="warning" %}
`ValueAsNumber` would avoid the string handling, and it reads whole numbers, so `12500.50` comes back as `0`. Read `ValueAsText` and convert it yourself wherever the amount can carry pence.
{% endhint %}

## Checking for NaN

`parseFloat` returns `NaN` for an empty field, and for anything the stripping did not anticipate. `NaN` fails every comparison silently, so without the check the script would fall through to the final `return` and quote a levy of zero — the same answer it gives for a genuinely small claim, and indistinguishable from it.

Testing for it explicitly means an unreadable amount is a decision the script has made rather than one it stumbled into. Returning `0.00` is one reasonable choice; returning `"Check the declared amount"` is another, and would show the problem to whoever is reading the quote.

## Ordering the thresholds

With more bands, test them from the largest down and give each only its lower bound:

```javascript
if (declared > 100000) { return String((1000).toFixed(2)); }
if (declared > 50000)  { return String((500).toFixed(2)); }
if (declared > 25000)  { return String((350).toFixed(2)); }
return String((100).toFixed(2));
```

Once £60,000 has failed the test for £100,000 there is no need to confirm it is below it. Writing each band as a range is the tempting alternative, and JavaScript reads it in a way that surprises people:

```javascript
// Always true, whatever declared holds
if (50000 < declared < 100000) { }
```

JavaScript evaluates that left to right: `50000 < declared` gives `true` or `false`, and comparing either of those to `100000` is always true. If you do want an explicit range, join two comparisons with `&&`.
