Business Logic: Processing Pipeline¶
Complete processing pipeline for calculatecost4 with exact formulas from source code.
1. Parse Input¶
Event body is parsed from JSON string to dict. Order.fromDict filters input keys to only those matching dataclass fields.
- Products deserialized via
Product.from_dict - Shipping deserialized via
Shipping.from_dict branchIdfrom order is propagated to every product
2. Enrich Products¶
For each product in the order:
price = PricingService.get_price(cprcode, branchId)
# If not found: float('inf')
originalPrice = PricingService.get_original_price(cprcode, branchId)
# If not found: 0
weight = ProductLookupService.get_product(cprcode).get('weight') or 0.25
weight = weight * quantity
isControlledProduct = cprcode in ControlledProductService.get_controlled_product_list()
rowTotal = max(price * quantity, 0)
settlementPrice = rowTotal
discountedRowTotal = max(rowTotal - discountFromCoupon, 0)
3. Calculate Weights¶
Weights are accumulated per schedule, then summed for the total.
4. Calculate Shipping¶
For each schedule in scheduleList:
if mode == EXPRESS and schedule is first:
expressFee = 50 # THB
if mode != NATIONWIDE:
nationwideConfig = "none"
Per-schedule fee via ShippingCalculator:
PICKUP: fee = 0
REGULAR: fee = ShippingPriceService.get_regular_price(lat, lon, brcode)
EXPRESS: fee = ShippingPriceService.get_regular_price(lat, lon, brcode)
NATIONWIDE: fee = ShippingPriceService.get_nationwide_price(postcode, weight, nationwideMode)
The regular/express price uses the Bangkok polygon API.
Aggregation:
deliveryFee = sum(schedule fees)
expressShippingCost = first schedule's expressFee
# 0 if no schedules
shippingPrice = shippingFee = sum(schedule fees)
5. Apply Coupons¶
Runs only if couponCodeList is non-empty.
Build CouponOrder payload:
CouponOrder(
products = [product.toDict() for each product],
branchId = order.branchId,
ownerId = order.ownerId,
shipping = order.shipping,
couponCodeList = order.couponCodeList,
subTotal = 0,
grandTotal = 0,
totalExcludeControlledProducts = 0,
expressShippingCost = expressShippingCost,
deliveryFee = 0,
totalWeight = totalWeight,
)
Call CouponService.check_coupons(order_dict) which returns a DiscountResult.
DiscountResult.discounts is a list of Discount, each containing:
| Field | Type |
|---|---|
| coupon | str |
| discount | float |
| bogoDiscount | float |
| two4Discount | float |
| percentageDiscount | float |
| freeshipping | bool |
| shippingDiscount | float |
Aggregation formulas:
cartDiscount = sum(d.discount for d in discounts)
bogoDiscount = sum(d.bogoDiscount for d in discounts)
two4Discount = sum(d.two4Discount for d in discounts)
percentageDiscount = max(d.percentageDiscount for d in discounts) * subTotal
# 0 if no discounts
freeShipping = any(d.freeshipping for d in discounts)
calculatedShippingDiscount = sum(d.shippingDiscount for d in discounts)
shippingDiscount = deliveryFee if freeShipping
min(calculatedShippingDiscount, deliveryFee) otherwise
6. Apply Vouchers¶
For each voucherId in the order:
Validity check (all must be true):
voucher.isActive == True
voucher.usedOnOrder is empty # not already redeemed
owner matches # if both voucher.usedOnOwner and order.ownerId are set
Aggregation:
7. Calculate Totals¶
subTotal = max(sum(product.rowTotal for all products), 0)
discountedDeliveryFee = max(deliveryFee - shippingDiscount, 0)
grandTotal = max(
subTotal
+ discountedDeliveryFee
+ expressShippingCost
- cartDiscount
- bogoDiscount
- voucherDiscount,
0
)
totalExcludeControlledProducts = grandTotal - sum(
product.rowTotal for controlled products
)
totalDiscount = cartDiscount
+ bogoDiscount
+ two4Discount
+ voucherDiscount
+ percentageDiscount
8. Serialize¶
Order.toDict() outputs a flat dict containing all computed scalar fields plus nested structures:
productList-- enriched product dictsshipping-- shipping objectvalidVouchers-- list of vouchers that passed validityinvalidVouchers-- list of vouchers that failed validitydiscountResult-- fullDiscountResultfrom coupon servicesummary--TotalSummarywith final totals