updates on the miler page and the create order calculations as well

This commit is contained in:
2026-10-07 17:18:42 +05:30
parent ff1b795292
commit 3d07ea8170
10 changed files with 489 additions and 99 deletions

92
src/lib/orderPricing.js Normal file
View File

@@ -0,0 +1,92 @@
/**
* The delivery charge shown and sent (as `finalprice`) when ops create orders —
* the single order form and bulk upload. The backend stores the figure as
* given, so this IS the price the client is billed.
*
* What it replaces, in both pages:
* - A rate card value of 0 was overwritten by a made-up default
* (`Number(x) || 40`, `|| 10`, `|| 2`): a card set to "₹15 per km, no base
* fee, no free km" was charged ₹40 plus ₹15 for each km after the first 2.
* - A client without a rate card was priced off ANOTHER client's card
* (`list[0]`), or a hard-coded ₹40 + ₹10/km after 2 km.
* - The first card found for the client was used even if Inactive, and the
* Pricing page's "priority" was ignored.
*/
/**
* Doormile's standard rate, for a client with no rate card: ₹15 per km, at
* least 1 km billed. Without the minimum a trip under 1 km (or a distance the
* router rounded to 0) priced at ₹0, and the backend treats a 0 `finalprice` as
* "not given" and re-prices the booking from another client's card.
*/
export const STANDARD_RATE = Object.freeze({
baseprice: 0,
basedistance: 0,
priceperkm: 15,
minimumkm: 1,
isStandard: true,
});
/** A rate value as a number; an empty or invalid value is 0, never a default. */
const amount = (value) => {
const n = Number(value);
return Number.isFinite(n) && n >= 0 ? n : 0;
};
const isActive = (rule) => !rule?.status || String(rule.status).toLowerCase() === 'active';
/** Inside the card's effectivefrom / effectiveto window (either may be unset). */
const inEffect = (rule, now = Date.now()) => {
const from = rule?.effectivefrom ? Date.parse(rule.effectivefrom) : NaN;
const to = rule?.effectiveto ? Date.parse(rule.effectiveto) : NaN;
return (Number.isNaN(from) || from <= now) && (Number.isNaN(to) || to >= now);
};
/** The Pricing page's priority: lower wins; unset is 1, and 0 stays 0. */
const priorityOf = (rule) => {
const n = Number(rule?.priority);
return rule?.priority == null || rule.priority === '' || !Number.isFinite(n) ? 1 : n;
};
/**
* The rate card for a client: its Active rules, the lowest priority number
* first (the Pricing page's "lower wins"), newest on a tie. A Doormile-wide
* card (no client) applies next; failing both, the standard rate. Never
* another client's card.
*/
export function pickRateCard(pricingList, tenantId, now = Date.now()) {
const rules = (Array.isArray(pricingList) ? pricingList : []).filter((r) => isActive(r) && inEffect(r, now));
const byPriority = (a, b) => priorityOf(a) - priorityOf(b) || amount(b.pricingid) - amount(a.pricingid);
if (tenantId != null && String(tenantId) !== '' && String(tenantId) !== '0') {
const own = rules.filter((r) => String(r.tenantid) === String(tenantId)).sort(byPriority);
if (own.length) return own[0];
}
const doormileWide = rules.filter((r) => r.isdefault || !r.tenantid || String(r.tenantid) === '0').sort(byPriority);
return doormileWide[0] || STANDARD_RATE;
}
/**
* The charge for a trip of `distanceKm` on `rate`: the base price covers the
* first `basedistance` km, every km after that is `priceperkm`. Rounded to
* paise.
*/
export function chargeForDistance(distanceKm, rate = STANDARD_RATE) {
const km = Math.max(amount(distanceKm), amount(rate?.minimumkm));
const base = amount(rate?.baseprice);
const freeKm = amount(rate?.basedistance);
const perKm = amount(rate?.priceperkm);
const charge = km <= freeKm ? base : base + (km - freeKm) * perKm;
return Math.round(charge * 100) / 100;
}
/** "₹15 / km" style labels for the rate card panel. */
export function describeRate(rate) {
const base = amount(rate?.baseprice);
const freeKm = amount(rate?.basedistance);
return {
base: base > 0 ? `₹${base}${freeKm > 0 ? ` (first ${freeKm} km)` : ''}` : 'No base fee',
perKm: `₹${amount(rate?.priceperkm)} / km${amount(rate?.minimumkm) > 0 ? ` (min ${amount(rate.minimumkm)} km)` : ''}`,
source: rate?.isStandard ? 'Standard rate (no client rate card)' : 'Client rate card',
};
}