Let's talk
pricing

A three-month booking was quoted at one month's price

Proposal totals ignored how long the campaign ran, then a save that touched nothing re-priced a quote the client had already seen. What the formula was missing.

·

You quote a client three months on a hoarding. The monthly rate is on the card, the mounting and printing are one-off, and the total on the proposal reads the same as it would for one month. Nobody typed a wrong number. The proposal simply had nowhere to put how long the campaign ran, so the rate was never multiplied by anything.

The reverse mistake was waiting on the other side. Mounting and printing are paid once, and they sat in the same bracket as the monthly rate. The obvious fix, multiply everything by the months, would have charged twelve mountings on a twelve-month booking. The formula was wrong in two directions at once, and fixing one without the other would have made it worse.

Then, after the fix, a second fault: opening a dated proposal and pressing Save without touching anything wiped the campaign dates, and with them the month count. A three-month quote a client had already seen silently became a one-month quote on a save that looked like nothing.

What it cost is the thing a media owner most wants not to happen: a quote sent at the wrong price, and the choice afterwards between honouring it and correcting it.

What was actually going on

The proposal carried no dates, so the rate expression had no month term. When the client asked for true pro rata rather than round-up, the change surfaced two more faults that only edge cases show. The first was tidiness: rounding the month fraction to four decimal places looks harmless and corrupts money. One month plus a day became 1.0323 months, which against a rate of a lakh a month is four rupees adrift of the correct 103,225.81. Rupee totals should round; fractions of a month should not.

The second was month ends. A booking from 31 January to 28 February is 29 days. Adding one month to 31 January and clamping to February’s last day put the anniversary inside the window, so it priced at 1.03 months, while a clean 31-day January priced at exactly 1.00. The shorter booking cost more.

And there was a third copy of the formula in the office portal, used to preview the figure while the form is being filled in, so a corrected server and an uncorrected form would have disagreed on screen. Our own demo data showed the shape of a unit mistake too: lump sums had been written into columns that hold a per-square-foot rate, so the form prefilled one gantry with 2.25 crore of mounting. The same lesson is in convert units at the boundary.

What we changed

One function now counts billable months by walking the calendar, month by month, pro rata, and every place that needs the figure calls it: the server, the form’s live preview and every generated document. The fraction is returned unrounded and only the rupee total rounds; a test pins the exact figure so nobody re-introduces the tidying. Month-end starts run to the end of the target month, so end-of-month to end-of-month is a whole number of months, and stopping a day short prices at just under one. A test asserts that a shorter booking can never out-price a longer one, which is the property that matters and would have caught the original fault.

The edit form now loads the dates it saves. The campaign window is printed on the proposal view under the same two labels the form uses, with the month count beside the end date, after the client asked where the dates were and they turned out to be on the page under a third name nobody had typed. The deck’s tables and the cost sheet gained Start, End and Months columns, each line resolving its own window so a row cannot contradict its own total. The workbook was generated from a live proposal and read back: dates present, total 157,589, matching the screen.

We also made one mistake of our own on the way. While fixing the formula, we changed the campaign’s stored rate from a monthly figure to a contract value. That was not in the agreed scope and would have silently multiplied a number clients had already seen on quotes. It was caught by diffing the names of failing tests against a clean baseline, and reverted.

What it did not fix

The change went live on 11 September with a consequence the client agreed to in advance: every existing proposal re-prices the moment it is next saved. A single day now bills one thirty-first of a month rather than a whole one. Both are what pro rata means, and both are real changes from the day before.

The log does not record how many proposals had gone out at the old price. And this fix does not check a quoted rate against the purchase order that follows it; there is nothing yet on the order that points back to the proposal it came from.

The mechanism

A rate that recurs and a charge that is paid once cannot share a bracket: the total is rate times months plus the one-offs, never the sum times months. The month count is a calendar walk, not a division by thirty, because the first and last days of a month are calendar facts and a thirty-day step drifts off both within two months.

The rule lives in exactly one place. Why your quoting spreadsheet eventually lies is the same finding from a different product: the moment a formula has two copies, the less-watched copy is the one that prices a quote.

Every proposal AdBoard produces now prints the window it was priced over, which is the only way a client and an owner can both check the total against the dates.

This came out of building Sazinga AdBoard

Every site, every booking, every invoice — in one place. The problem above is one we met while building it, and what we did about it is in the product.

If you run something like this, tell us how it works today and we will tell you what it would take to move.