
Security News
Risky Biz Podcast: Making Reachability Analysis Work in Real-World Codebases
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
@restorecommerce/cart
Advanced tools
[![Build Status][build]](https://travis-ci.org/restorecommerce/cart?branch=master)[![Dependencies][depend]](https://david-dm.org/restorecommerce/cart)[![Coverage Sta
An backend agnostic purely data-driven shopping cart that can be used on client- and server side.
Cart Instantiation:
const cart = new Cart({
serializer: new MockSerializer(),
shippingMethod: new Courier({
source: JSON.stringify(data.publicDHL),
shipping: {originCountry: 'DE'}
}),
taxOriginCountry: 'DE',
taxes: {
vat_standard: {
rate: new Decimal(1.19),
desc: '+ VAT 19%'
},
vat_reduced: {
rate: new Decimal(1.07),
desc: '+ VAT 7%'
}
}
});
Setting serializer
and shippingMethod
is optional.
setDestinationCountry(country: string)
cart.setDestinationCountry('LV');
getShippingMethod()
cart.getShippingMethod();
Output:
Courier {
_source: {
assumptions: {
currency: 'eur',
dimensions: [Object],
length: 'mm',
ranges: [Object],
weight: 'gram'
},
zones: {
'1': [Object],
'2': [Object],
'3': [Object],
'4': [Object],
'5': [Object],
'6': [Object],
'7': [Object],
'8': [Object],
national: [Object]
}
},
_shipping: {
destinationCountry: 'LV',
originCountry: 'DE' }
}
getShipping()
There is no setShipping
setter, since info about shipping is taken from ShippingMethod
's source
property.
cart.getShipping(); // calculates shipping cost
Output:
{
price: '15.99',
taxType: 'vat_standard',
maxWeight: 5000,
type: 'package',
zone: '1',
human: {
zone: '1 (all EU countries)',
offer: 'Package up to 5kg',
}
}
getSerializer()
cart.getSerializer();
getTaxRates()
cart.getTaxRates();
Output:
{
taxes: {
vat_standard: {
rate: '1.19',
desc: '+ VAT 19%'
},
vat_reduced: {
rate: '1.07',
desc: '+ VAT 7%'
}
}
}
addItems(items: IItem[])
cart.addItems([{
sku: 'cr2-blue',
price: new Decimal('12.95'), // Price
taxType: 'vat_reduced',
weight: 210, // grams
height: 2.20, // cm
width: 13.5, // cm
depth: 8.22, // cm
quantity: 7,
}, {
sku: 'cr5-red',
price: new Decimal('1.10'),
taxType: 'vat_standard',
weight: 210, // grams
height: 2.20, // cm
width: 13.5, // cm
depth: 8.22, // cm
quantity: 15,
}, {
sku: 'cr3-yellow',
price: new Decimal('2.48'),
taxType: 'vat_standard',
weight: 210, // grams
height: 2.20, // cm
width: 13.5, // cm
depth: 8.22, // cm
quantity: 3,
}]);
remItem(sku: string)
cart.remItem('cr3-yellow');
getItems()
cart.getItems();
Output:
[
{
sku: 'cr2-blue',
price: 12.95,
taxType: 'vat_reduced',
weight: 210,
height: 2.2,
width: 13.5,
depth: 8.22,
quantity: 7
},
{
sku: 'cr5-red',
price: 1.10,
taxType: 'vat_standard',
weight: 210,
height: 2.2,
width: 13.5,
depth: 8.22,
quantity: 15
}
]
setCustomer(customer: ICustomer)
cart.setCustomer({
type: CustomerType.COMMERCIAL,
});
setCustomerType(type: CustomerType)
This modifies the customer.
.
cart.setCustomerType(CustomerType.PRIVATE);
getCustomer()
cart.getCustomer();
Output:
{
type: 1 // 0 - COMMERCIAL / 1 - PRIVATE
}
modifyItem(item: any)
cart.modifyItem({
sku: 'cr5-red',
// no update for other Cart properties as no change
quantity: 10, // change only quantity
});
modifyItemQuantity(sku: string, quantity: number)
cart.modifyItemQuantity('cr5-red', 5); // adds 5 to initial quantity
getItemQuantity(sku: string)
`Amount of cr2-blue = ${cart.getItemQuantity('cr5-red')}`;
Output:
Amount of cr5-red = 15 // 10 + 5
getItemCount()
`Amount of unique products = ${cart.getItemCount()}`;
Output:
Amount of unique products = 2
getGrandQuantity()
`Amount of all products = ${cart.getGrandQuantity()}`;
Output:
Amount of all products = 22 // 15 + 7
getTaxes(keepOriginalTaxType?: boolean )
cart.getTaxes();
Output:
netPrice
and rate
are instances of Decimal
.
{
vat_standard: {
netPrice: '32.49',
rate: '1.19',
desc: '+ VAT 19%'
},
vat_reduced: {
netPrice: '90.65',
rate: '1.07',
desc: '+ VAT 7%'
}
}
static round(money: Money)
Parameter could be number
|string
|Decimal
. Returns string.
Cart.round(1.120); // '1.12'
Cart.round('1.123'); // '1.13'
Cart.round(new Decimal(1.125)); // '1.13'
Cart.round(new Decimal('1.127')); // '1.13'
getTotalNet()
Total net (without taxes).
Cart.round(cart.getTotalNet()); // '123.14'
Calculation:
1) customer.billing.countryCode === 'LV' => VAT + 19% / 7%
2) cr2_blue: Price * quantity => 12.95 * 7 = 90.65
3) cr5_red: Price * quantity => 1.10 * 15 = 16.5
4) Max Weight of all items = 22 items * 210 grams = 4620 grams =>
shipping = 15.99 euro for package less than 5000 grams to EU
5) sum = 90.65 + 16.5 + 15.99 = 123.14
getTotalGross()
Total gross (with taxes).
Cart.round(cart.getTotalGross()); // '135.66'
Calculation:
1) cr2_blue => cr2_blue + VAT 7% = 90.65 * 1.07 = 96.9955
2) cr5_red => cr5_red + VAT 19% = 16.5 * 1.19 = 19.635
3) shipping => shipping + VAT 19% = 15.99 * 1.19 = 19.0281
4) sum => 96.9955 + 19.635 + 19.0281 = 135.6586
5) round(135.6586) = 135.66
More examples of using the Cart
can be found in test/index.ts
.
Method | Description |
---|---|
getItems(): IItems / undefined | Get Items |
private setItems(items: IItem[]): void | Set items |
getCustomer(): ICustomer / undefined | Get customer |
setCustomer(customer: ICustomer): void | Set customer |
getShippingMethod(): IShippingMethod/ undefined | Get shipping method |
setShippingMethod(shippingMethod: IShippingMethod): void | Set shipping method |
getSerializer(): ISerializer / undefined | Get serializer |
setSerializer(serializer: ISerializer): void | Set serializer |
getTaxRates(): TaxRates | Get tax rates |
private setTaxRates(taxRates: TaxRates) | Set tax rates |
setCustomerType(type: CustomerType): void | Set customer's type (PRIVATE /COMMERCIAL ) |
setDestinationCountry(country: string): void | Set destination country |
addItems(items: IItem[]): void | Add item/items to the cart |
remItem(sku: string): void | Remove item from the cart by SKU (Stock Keeping Unit) |
modifyItem(item: any) | Update item |
modifyItemQuantity(sku: string, quantity: number): void | Modify item's quantity |
getItemCount(): number | Get item count |
getItemQuantity(sku: string): number | Get quantity of particular item |
getGrandQuantity(): number | Item count x quantity of each item |
getTaxes(keepOriginalTaxType?: boolean ): { [taxType: string]: { netPrice: Decimal, rate: Decimal, desc: string, price: Decimal } } | Get tax list, with ratios and additive costs |
getTotalNet(): number | Get sum of item and shipping costs (taxes excluded) |
getTotalGross(): number | Get sum of item and shipping costs (taxes included) |
getShipping(): { price: Money, [prop: string]: any } | Get item's shipping info |
static round(money: Money): string | Convert money type (number /string /Decimal ) to string with rounding |
To lint, transpile and test, run:
npm test
IShippingMethod
interface implementations:
Courier Plans:
For VAT calculation, the cart applies the EU ruleset for taxation which is exemplified in the following with a shop that is located in Germany and customer location location/ type being:
This also works for other countries as it's just a simplification of this for most countries. Sales taxes and other country specific taxes can be added.
Legal background:
FAQs
[![Build Status][build]](https://travis-ci.org/restorecommerce/cart?branch=master)[![Dependencies][depend]](https://david-dm.org/restorecommerce/cart)[![Coverage Sta
We found that @restorecommerce/cart demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
This episode explores the hard problem of reachability analysis, from static analysis limits to handling dynamic languages and massive dependency trees.
Security News
/Research
Malicious Nx npm versions stole secrets and wallet info using AI CLI tools; Socket’s AI scanner detected the supply chain attack and flagged the malware.
Security News
CISA’s 2025 draft SBOM guidance adds new fields like hashes, licenses, and tool metadata to make software inventories more actionable.