@financial-times/n-pricing

Consistent pricing transformations

Stats

StarsIssuesVersionUpdatedCreatedSize
@financial-times/n-pricing
5.4.03 months ago4 years agoMinified + gzip package size for @financial-times/n-pricing in KB

Readme

n-pricing

💷 Consistent currency data, pricing and transformations

Pricing needs to remain consistent across the site, from barrier, to marketing popup, to signup confirmation page.

This small library allows the validation and manipulation of currencies and pricing, and performs pricing transformations.

Classes

  • Currency
  • Price
  • Monthly
  • Quarterly
  • Yearly

Installation

npm install --save @financial-times/n-pricing

Currency

const Currency = require('@financial-times/n-pricing').Currency;

Usage

let money = new Currency(); // { currency: 'GBP', symbol: '£', decimals: 2 }
money = new Currency('jpy'); // { currency: 'JPY', symbol: '¥', decimals: 0 }

Validation

new Currency('NOT_A_CURRENCY')._valid // false

Price

const Price = require('@financial-times/n-pricing').Price;

Usage

new Price().get() // £0.00

new Price({ value: 1 }).get() // £1.00

new Price({ value: 1, currency: 'JPY' }).getAmount()
// { value: '¥1.00', currency: 'JPY', symbol: '¥', nativeSymbol: '¥' }

new Price({ value: 1, currency: 'HKD', nativeSymbol: '$' }).price
// { amount: { value: 'HK$1.00', currency: 'HKD', symbol: 'HK$', nativeSymbol: '$' } }

new Price({ value: 1, currency: 'HKD', nativeSymbol: '$', trimDecimalsWhenWhole: true }).price
// { amount: { value: 'HK$1', currency: 'HKD', symbol: 'HK$', nativeSymbol: '$' } }

Discounting

new Price({ value: 1 }).discount( -0.5 ).get() // £0.50

Comparing

The .compare() method returns savings in value difference and as a percentage.

Negative values indicate a markup, i.e. the stored value of the object is higher than the value we are comparing against.

new Price({ value: 10 }).compare( 8 ) // { value: '-£2.00', percentage: '-20%'}

new Price({ value: 8 }).compare( 10 ) // { value: '£2.00', percentage: '25%'}

Formatted amounts

The .getAmountFormatted() method returns values formatted based on the options.

The options are:

  • trimDecimalsWhenWhole - Boolean that determines whether to remove the decimal part of the amount if it is a whole number. Default value is false.
new Price({ value: 10 }).getAmountFormatted({ trimDecimalsWhenWhole: true }); // Returns '£10'
new Price({ value: 10.25 }).getAmountFormatted({ trimDecimalsWhenWhole: true }); // Returns '£10.25'

Uninterpolated

You're able to return pricing and percentage information without symbols interpolated by passing in an uninterpolated flag as follows:

NB: Only use this if you have some specific reason that falls outside the remit of this module.

new Price({ value: 1 }, { uninterpolated: true }).get() // 1.00

new Price({ value: 1, currency: 'JPY' }, { uninterpolated: true }).getAmount()
// { value: '1.00', currency: 'JPY', symbol: '¥', nativeSymbol: '¥' }

new Price({ value: 1 }, { uninterpolated: true }).discount( -0.5 ).get() // 0.50

new Price({ value: 10 }, { uninterpolated: true }).compare( 8 ) // { value: '-2.00', percentage: '-20'}

Price transformations

Monthly, Yearly & Quarterly

Offer pricing is either annual, monthly or quarterly. We often display pricing translated into its weekly cost.

Monthly, Yearly and Quarterly extend the Price class to offer some useful pricing transformations that allow for all alternative breakdowns of cost.

const Monthly = require('@financial-times/n-pricing').Monthly;
const Yearly = require('@financial-times/n-pricing').Yearly;
const Quarterly = require('@financial-times/n-pricing').Quarterly;

Usage

new Monthly({ value: 1 }).get('yearly') // £12.00

new Yearly({ value: 96.45 }).get('monthly') // £8.04

new Quarterly({ value: 30 }).get('yearly') // £120

new Monthly({ value: 1, currency: 'OMR', nativeSymbol: '﷼' }).getAmount('weekly')
// { value: '﷼ 0.231', currency: 'OMR', symbol: 'BD', nativeSymbol: '﷼' } }

new Monthly({ value: 1 }).price
/*
{
  yearly: {
    amount: { value: '£12.00', currency: 'GBP', symbol: '£', nativeSymbol: '£' }
  },
  monthly: {
    amount: { value: '£1.00', currency: 'GBP', symbol: '£', nativeSymbol: '£' }
  },
  weekly: {
    amount: { value: '£0.23', currency: 'GBP', symbol: '£', nativeSymbol: '£' }
  },
  daily: {
    amount: { value: '£0.04', currency: 'GBP', symbol: '£', nativeSymbol: '£' }
  }

}
*/

Comparing savings

let yearlyPrice = new Yearly({ value: 10 });
let monthlyPrice = new Monthly({ value: 1 });

yearlyPrice.compare( monthlyPrice.get('yearly') )
// { value: '£2.00', percentage: '20%'}
// annual pricing at £10 offers a 20% saving over paying £1 a month

How exactly are pricing transformations made?

We use big.js to handle decimal arithmetic.

We use the ROUND_UP rounding method in our calculations: http://mikemcl.github.io/big.js/#rm

Rounds away from zero.

Offers originally have their priced expressed as either x per Year, x per Month or x per Quarter. From this we may want to display an expression of the price weekly or daily.

Using the table below. input 12 per Year would be displayed as output 1 per Month.

Input Original Price Expression (val) Output Expression Calculation
Yearly Monthly val/12
Quarterly val/4
Weekly val/52
Daily val/365
Monthly Yearly val*12
Quarterly val*3
Weekly (val*12)/52
Daily (val*12)/365
Quarterly Yearly val*4
Monthly val/3
Weekly val/13
Daily (val*4)/365

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.