Money and prices
Minor units, currencies, price lists and pack sizes.
Amounts are minor units
Every amount is a whole number in the currency's smallest unit: pesewas for Ghana cedis. 1200 is GH₵ 12.00, 9000 is GH₵ 90.00. There are never decimals, so nothing is lost to rounding.
The shop's currency is in GET /shop as currency (GHS, NGN, KES, ZAR, USD, EUR or GBP):
const money = (amount, currency) =>
new Intl.NumberFormat(undefined, { style: 'currency', currency }).format(
amount / 100,
);
money(1200, 'GHS'); // "GH₵12.00"Where prices live
A product has one or more versions (sizes, colours: a variant each). Each version has:
sellingPrice: its price for one unit, at the shop's first price type.prices: its price at each price type the shop shows online.sellingUnits: the packs it also sells in (a carton of 24), each with its ownsellingPriceandprices.
{
"priceTypes": [
{ "id": null, "name": "Retail" },
{ "id": "9badb858-…", "name": "Wholesale" }
],
"versions": [
{
"variantId": "1db29704-…",
"sellingPrice": 1200,
"prices": [
{ "priceListId": null, "sellingPrice": 1200 },
{ "priceListId": "9badb858-…", "sellingPrice": 1000 }
],
"sellingUnits": [
{
"id": "c22d51bf-…",
"name": "Pack of 10",
"sellingPrice": 12000,
"prices": [{ "priceListId": null, "sellingPrice": 12000 }]
}
]
}
]
}Price types
Shops sell at more than one price: retail and wholesale, adult and kids. priceTypes lists those the shop offers online; id: null is Retail. Let customers pick one and send its id as priceListId on each order line. Leave it out for Retail.
Taxes and delivery
The order's total includes the shop's taxes and any delivery fee, worked out by Cashiar. Show the line prices while the customer shops, and the total the order answers with at checkout.
Delivery fees are in GET /shop: delivery.fee is the usual fee, and delivery.zones lists places with their own fee. Send the zone's name as deliveryZone to charge it.