updates on the miler page and the create order calculations as well
This commit is contained in:
92
src/lib/orderPricing.js
Normal file
92
src/lib/orderPricing.js
Normal 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',
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user