Koriko is a courier service library to estimate cost and time to deliver the packages. This library is very customizable, and can add custom estimation pipeline to the existing API.
- Check out the documentation
- Try the live demo as mentioned above
So if you have a courier service and wants to
- estimate cost of the package along with coupon/offers configuraion
- estimate delivery time of the package along with cost, coupon/offers and fleet configurations
- estimateCost API to estimate cost along with coupon configuration.
- custom estimattor can be added via API (Ex. deduct tax along with totalCost of delivery)
- estimateTime API to allocate shipping/ and fleet
- custom package allocation/ maximzation strategy (default maximizeByNumberOfPackages)
- API can be consumed by any Javascript client/ server (can expose as REST API as well)
This is a Node.js library and application
Before installing, download and install latest Node.js.
Installation is done using the
npm install
command:
$ npm install
To run the console application,
$ npm start ./__testinputs__/use_case_1.txt
$ npm start ./__testinputs__/use_case_2.txt
Output is ordered by deliveryEstimateTimeHrs
You can place your input test files in __testinputs__
directory and run with your filename.
$ npm start ./__testinputs__/<file-name>.txt
You can configure coupons and settings via data/db.json
file.
To generate docs site offline usage run,
$ npm run doc
To develop the web client run,
$ npm run web:dev
To build the web client run,
$ npm run web:build
To run the tests,
$ npm run test
For see the coverage,
$ npm run test:coverage
For linting run,
$ npm run lint
- composable functional programming style followed. Ex. customDeductTax(applyCoupon(estimateCost()))
- 0 / 1 knapsack algorithm is used to solve the maximization problem (with Dynamic programming approach)
- custom package allocation/ maximzation strategy is customizable (default maximizeByNumberOfPackages)
- Priority Queue is implemented for fleet allocation
import { makeDeliveryEstimator } from '../../lib'
const baseCost = 100
const packages = [{
"id": 'PKG1',
"weightKg": 5,
"distanceKm": 5, "offerCode": 'OFR001'
},
{
"id": 'PKG2',
"weightKg": 10,
"distanceKm": 60
},{"...": "..."}]
const coupons = [{
"code": "OFR001",
"discountPercentage": 10,
"minDistanceKm": 0,
"maxDistanceKm": 200,
"minWeightKg": 70,
"maxWeightKg": 200
},
{"...": "..."}]
const settings = { "costPerKg": 10, "costPerKm": 5 }
const estimator = makeDeliveryEstimator({ baseCost, coupons, settings })
// get package cost estimation with coupons if applicable
const packagesWithCost = estimator.estimateCost(packages)
console.table(packagesWithCost)
import { makeDeliveryEstimator } from '../../lib'
const baseCost = 100
const packages = [{
"id": 'PKG1',
"weightKg": 5,
"distanceKm": 5, "offerCode": 'OFR001'
},
{
"id": 'PKG2',
"weightKg": 10,
"distanceKm": 60
},{"...": "..."}]
const coupons = [{
"code": "OFR001",
"discountPercentage": 10,
"minDistanceKm": 0,
"maxDistanceKm": 200,
"minWeightKg": 70,
"maxWeightKg": 200
},
{"...": "..."}]
const settings = { "costPerKg": 10, "costPerKm": 5 }
const fleetDetail = { numberOfVehicles: 2, maxSpeedKmPerHr: 70, maxLoadKg: 200 }
const estimator = makeDeliveryEstimator({ baseCost, coupons, settings })
// get shipments with allocated packages, along with cost and delivery time estimations
const shipments = estimator.estimateTime(packages, fleetDetail)
console.table(shipments)
....
....
import baseEstimatorWithCoupon from './ib/core/cost-estimator-with-coupon'
function estimatorWithTaxDeduction (options) {
const packageItem = baseEstimatorWithCoupon(options)
return {
...packageItem,
totalCost: packageItem.totalCost - packageItem.totalCost * 0.18 // dedcut 18% Tax (use case)
}
}
// get package cost estimation along with coupons if applicable and tax dedction
const packagesCostWithTax = estimator.estimateCost(packages, estimatorWithTaxDeduction)
....
....
let defaultCostStragey; // if not defined, default strategy is used
let defaultTimeStragey; // if not defined, default strategy is used
function maximizeByTotalCost(packages) {
return packages.map(item => item.totalCost)
}
// get shipments with allocated packages, along with cost and delivery time estimations
const shipments = estimator.estimateTime(packages, fleetDetail, defaultCostStragey,
defaultTimeStragey maximizeByTotalCost)
{
"id": 'PKG1', //string
"weightKg": 5, //number
"distanceKm": 5, //number
"offerCode": 'OFR001' //string (optional)
}
{
"code": "OFR001", // string
"discountPercentage": 10, // number
"minDistanceKm": 0, // number
"maxDistanceKm": 200, // number
"minWeightKg": 70, // number
"maxWeightKg": 200 // number
}
{
"costPerKg": 10, //string
"costPerKm": 5 // string
}
{
"numberOfVehicles": 2, // number
"maxSpeedKmPerHr": 70, // number
"maxLoadKg": 200 // number
}
class Package {
/**
* @property {string} uuid internal unique package Id
*/
uuid = `${uuid()}`
/**
* @property {string} id Package Id
*/
id = `${uuid()}`;
/**
* @property {number} weightKg Package Weight in Kg
*/
weightKg = 0;
/**
* @property {number} distanceKm Package delivery distance in Km
*/
distanceKm = 0;
/**
* @property {string} offerCode Coupon code
*/
offerCode = '';
/**
* @property {number} cost Delivery cost
*/
cost = 0;
/**
* @property {number} discountPercentage Discounted percentage if coupon applied
*/
discountPercentage = 0;
/**
* @property {number} discount Discount amount
*/
discount = 0;
/**
* @property {number} totalCost Total cost of delivery
*/
totalCost = 0;
/**
* @property {number} deliveryEstimateTimeHrs Delivery estimate hours
*/
deliveryEstimateTimeHrs = 0
/**
* @property {number} actualEstimateHrs Actual estimate hours
*/
actualEstimateHrs = 0
}
class Shipment {
/**
* @property {string} Shipment Id
*/
id = `${uuid()}`
/**
* @property {Array<Package>} packages
*/
packages = []
/**
* Get shipmetn weight
* @returns {number} Total shipment weight
*/
getWeightkg ()
}