Each shipping option has a shipping rules section:
message ShippingOption {
string name = 1;
ShippingType type = 2;
repeated CountryCode regions = 3;
ShippingRules shippingRules = 4;
repeated Service services = 5;
}
The shippingRules object looks like:
message ShippingRules {
RuleType ruleType = 1;
repeated Rule rules = 2;
message Rule {
uint32 minRange = 1;
uint32 maxRange = 2;
uint64 price = 3;
}
enum RuleType {
QUANTITY_DISCOUNT = 0;
FLAT_FEE_QUANTITY_RANGE = 1;
FLAT_FEE_WEIGHT_RANGE = 2;
}
}
The object must be of only one ruleType
but maybe have more than one rule
.
Each rule specifies a min and max value as well as a price. The ruleType
determines how the shipping is calculated using the min and max.
For example the following says if you buy between 5 and 10 items then 10000 satoshi will be subtracted from the shipping. If you buy between 11 and 20 then 20000 satoshi will be subtracted from shipping.
{
"ruleType": "QUANTITY_DISCOUNT",
"ruels": [
{
"minRange": 5,
"maxRange": 10,
"price": 10000
},
{
"minRange": 11,
"maxRange": 20,
"price": 20000
}
]
}
The following is reference code for calculating the shipping price. The itemShipping
object is the running shipping total for this item and starts equal to the price of the selected service
times the quantity purchased.
for _, rule := range option.ShippingRules.Rules {
switch option.ShippingRules.RuleType {
case pb.Listing_ShippingOption_ShippingRules_QUANTITY_DISCOUNT:
if item.Quantity >= rule.MinRange && item.Quantity <= rule.MaxRange {
rulePrice, err := n.getPriceInSatoshi(listing.Metadata.PricingCurrency, rule.Price)
if err != nil {
return 0, err
}
itemShipping -= rulePrice
}
case pb.Listing_ShippingOption_ShippingRules_FLAT_FEE_QUANTITY_RANGE:
if item.Quantity >= rule.MinRange && item.Quantity <= rule.MaxRange {
rulePrice, err := n.getPriceInSatoshi(listing.Metadata.PricingCurrency, rule.Price)
if err != nil {
return 0, err
}
itemShipping = rulePrice
}
case pb.Listing_ShippingOption_ShippingRules_FLAT_FEE_WEIGHT_RANGE:
weight := listing.Item.Grams * float32(item.Quantity)
if uint32(weight) >= rule.MinRange && uint32(weight) <= rule.MaxRange {
rulePrice, err := n.getPriceInSatoshi(listing.Metadata.PricingCurrency, rule.Price)
if err != nil {
return 0, err
}
itemShipping = rulePrice
}
}
}