@dutchfurniturefulfilment/skik-client
Version:
Javascript package for integrating a SKIK configurator inside web projects.
148 lines (108 loc) • 5.95 kB
Markdown
# Injecting product prices and displaying a total price
The SKIK configurator has built-in facilities to automatically calculate total prices depending on the parts selected by a configurator user. In order for the configurator to do this, the prices must be explicitly given to a `Client` instance.
## Global rules concerning the expression of prices
- All prices are expected to be in the [**EUR** currency](https://en.wikipedia.org/wiki/Euro) at all times.
- All prices are expected to **include** [VAT](https://en.wikipedia.org/wiki/Value-added_tax).
_Value-added Tax, BTW in the Netherlands._
- All price values are expected to be quantified in the **cents unit**.
_For example: **EUR 12,50** is expressed as `1250`.
In code, prices are at all times expected to be of type `Number`._
- 2 prices are used for all products:
- **Original price**
- **Is** the price for a product, **excluding any discount**.
- **Is** by convention named `originalPrice` in code.
- **Discount price**
- **Is** the price for a product, **including potential discount**.
- **Is** by convention named `discountPrice` in code.
## Expressing price discounts, or absence thereof
If a certain product has no applicable discount, **discount-price** must for that product equal **original-price**. In any case, both properties are required to keep API signatures consistent:
```typescript
const productWithDiscount: SKIKClient.ProductPrices = {
EANCode: "8714713074655",
originalPrice: 1250,
discountPrice: 1050,
};
// Products without discount have the `discountPrice`
// value set to the same value as `originalPrice`:
const productWithoutDiscount: SKIKClient.ProductPrices = {
EANCode: "8714713074662",
originalPrice: 1600,
discountPrice: 1600,
};
```
## Injecting product prices
**Only if prices for _all products_ are given, the configurator will attempt to calculate the sum of prices for any given configuration.**
If price-data is not given, or is incomplete, no relative prices can be shown in the configurator interface, and no [`"price-changed"` events](../api/event-channels#price-changed) can be dispatched by the client instance.
### Retrieving EAN codes for all relevant products
The [`Client # getEANCodes()`](../api/client#getting-an-array-of-all-product-ean-codes) method can be used to obtain an array of all EAN codes for products that are used in the SKIK configurator. The method returns a `Promise` that resolves to the array of codes:
```typescript
const skikClient: SKIKClient.Client = SKIKClient.create({ /* ... */ });
const EANCodesPromise: Promise<string[]> = skikClient.getEANCodes();
/* =>
[
"8714713074655",
"8714713074662",
"8714713074679",
// ...
];
*/
```
_After retrieval, this returned array can be used as source for your price data query._
Let's assume a function called `pricesForEANCode` exists, that returns an object implementing the [`SKIKClient.ProductPrices`](../interfaces/prices#productprices) interface: a plain object as returned in this **pseudo-implementation**:
_In reality, product prices would of course be dynamically determined based on the given EAN code, instead of literal numbers._
```typescript
const pricesForEANCode = (code: string): SKIKClient.ProductPrices => ({
EANCode,
originalPrice: 1250,
discountPrice: 1050,
});
```
### Feeding back all required prices into the configurator
With our price retrieval implementation in place, it's time to decorate the `EANCodes` array we retrieved a Promise for earlier. This example uses `pricesForEANCode` to perform a map operation on the array of EAN codes:
```typescript
EANCodesPromise.then(function(EANCodes) {
const productData: SKIKClient.ProductPrices[] = EANCodes.map(function(code) {
return pricesForEANCode(code);
});
// ...
})
```
The `productData` variable should now be in the exact format expected by [`Client # setProductPrices()`](../api/client#setting-the-prices-for-products), the method we'll use to inject the price data.
```typescript
// Like before:
EANCodesPromise.then(function(EANCodes) {
const prices: SKIKClient.ProductPrices[] = EANCodes.map(function(code) {
return pricesForEANCode(code);
});
// But with injection:
skikClient.setProductPrices(prices);
// The data is formatted like this:
assert.equal(prices, [
{ EANCode: "8714713074655", originalPrice: 1250, discountPrice: 1050 },
{ EANCode: "8714713074662", originalPrice: 1600, discountPrice: 1600 },
{ EANCode: "8714713074679", originalPrice: 995, discountPrice: 995 },
// ...
]);
});
```
## Displaying a total price
The configurator does not implement a display of the total configuration price. Instead, it emits the [`"price-changed"`](../interfaces/event-channels#price-changed) event each time a mutation of the total price occurred. We can listen to these events to get [price mutation reports](../interfaces/prices#pricemutationreport) providing valuable information about the old and new prices:
```typescript
skikClient.on("price-changed", (mutationReport) => {
// Example data:
assert.equal(mutationReport, {
before: {
originalPrice: { cents: 1250, formatted: "€12,50" },
discountPrice: { cents: 1050, formatted: "€10,50" },
},
after: {
originalPrice: { cents: 2500, formatted: "€25,00" },
discountPrice: { cents: 2100, formatted: "€21,00" },
},
});
console.log(`The previous real price (including discount) was: `, mutationReport.before.discountPrice.formatted);
// > "The previous real price (including discount) was: €10,50"
console.log(`The new real price (including discount) is: `, mutationReport.after.discountPrice.formatted);
// > "The new real price (including discount) is: €21,00"
});
```