Skip to content

villaCalculateCost4 API Reference

Complete documentation of the endpoint, request/response schemas, and calculation logic.


Endpoint

Method Path Handler Purpose
POST /calculatecost4 calculatecost2Lambda.lambda_handler Calculate order cost

Deployment note: The current SAM template.yaml still routes both POST /calculatecost2 and POST /calculatecost3 to the same handler. These accept the identical JSON body. The canonical endpoint name going forward is /calculatecost4.


Request Schema -- POST /calculatecost4

Top-Level Fields

{
  "productList": [
    {
      "cprcode": 146098,
      "productName": "ice cream",
      "quantity": 2
    }
  ],
  "branchId": "1023",
  "voucherId": ["WNOB0OWQ"],
  "couponCodeList": ["9I7Y2KEY"],
  "basketId": "optional-uuid",
  "basketName": "optional string",
  "orderId": "172400000244",
  "orderDate": 1718989200,
  "ownerId": "567636a5-8794-40e0-8455-a85dea7a637d",
  "requestSubstitute": false,
  "specialComment": null,
  "noPlasticBags": false,
  "shipping": { "..." : "..." },
  "cartDiscountInfo": []
}

Extra keys in the request body are silently dropped. The Order.fromDict constructor filters to dataclass fields only.

Field Definitions

Field Type Required Default Notes
productList array[Product] Yes -- One or more products
voucherId array[string] No [] Voucher IDs to apply
basketName string No "" Passed through unchanged
basketId string No "" Passed through unchanged
branchId string No "1000" Store branch ID; applied to all products
orderId string No "" Passed through unchanged
orderDate number No 0 Unix timestamp; passed through
ownerId string No "" Used for voucher ownership validation
requestSubstitute boolean No false Passed through unchanged
specialComment string No null Passed through unchanged
noPlasticBags boolean No false Passed through unchanged
shipping Shipping No -- Shipping and delivery configuration
cartDiscountInfo array No [] Cart-level discount metadata
couponCodeList array[string] No [] Coupon codes to validate and apply

Product Object (Input)

Minimum required fields: cprcode, productName, quantity.

{
  "cprcode": 146098,
  "productName": "ice cream",
  "quantity": 1,
  "scheduleId": 2,
  "isPreOrder": false,
  "remark": ""
}
Field Type Required Default Notes
cprcode integer Yes -- Product code; used as DynamoDB key
productName string Yes -- Display name; passed through
quantity integer Yes -- Units to order
scheduleId integer No 0 Links product to shipping schedule slot
isPreOrder boolean No false Pre-order flag; passed through
remark string No "" Passed through unchanged

Computed product fields (price, originalPrice, rowTotal, discountedRowTotal, settlementPrice, weight, isControlledProduct) in the request are silently ignored.


Shipping Object

{
  "shippingType": "DELIVERY",
  "shippingPostcode": "10110",
  "shippingLat": 13.73204799,
  "shippingLon": 100.56762289,
  "shippingFirstName": "tor",
  "shippingLastName": "intanon",
  "shippingAddress": "595 Sukhumvit Rd",
  "shippingSubDistrict": "",
  "shippingProvince": "Bangkok",
  "shippingPhone": "061-002-0199",
  "shippingEmail": "",
  "shippingDate": 0,
  "brcode": 1023,
  "scheduleList": [ { "..." : "..." } ]
}
Field Type Default Notes
scheduleList array[Schedule] -- Delivery schedule slots
shippingType enum "PICKUP" "DELIVERY" or "PICKUP"
shippingPostcode string "10110" Used for nationwide shipping rate lookup
shippingLat float 0 Latitude; used for Bangkok polygon check
shippingLon float 0 Longitude; used for Bangkok polygon check
shippingFirstName string "" Passed through
shippingLastName string "" Passed through
shippingAddress string "" Passed through
shippingSubDistrict string "" Passed through
shippingProvince string "" Passed through
shippingPhone string "" Passed through
shippingEmail string "" Passed through
shippingDate number 0 Passed through
brcode integer 1000 Branch code for polygon lookup

Schedule Object

{
  "scheduleId": 0,
  "mode": "NATIONWIDE",
  "dateTime": "2022-04-09T13:00:00.000Z",
  "deliveryFee": 0,
  "expressFee": 0,
  "nationwideMode": "DRY",
  "nationwideConfig": "",
  "pickingStatus": "",
  "date_slot": "",
  "booking_hour": 0
}
Field Type Values Notes
mode enum REGULAR, EXPRESS, NATIONWIDE, PICKUP Determines fee calculator
dateTime string ISO-8601 Passed through
scheduleId integer 0--N Links to productList[].scheduleId
deliveryFee number -- Overwritten by calculation
expressFee number -- Overwritten -- 50 THB if mode=EXPRESS and first schedule
nationwideMode enum DRY, FRESH, MIX Affects nationwide rate lookup
nationwideConfig string -- Set to "none" if non-nationwide
pickingStatus any -- Passthrough
date_slot any -- Passthrough
booking_hour any -- Passthrough

Response Schema

Success (HTTP 200)

The response body is the enriched order object produced by Order.toDict().

{
  "productList": [ "..." ],
  "shipping": { "..." : "..." },

  "basketName": "",
  "basketId": "",
  "branchId": "1023",
  "orderId": "",
  "orderDate": 0,
  "ownerId": "",
  "requestSubstitute": false,
  "specialComment": null,
  "noPlasticBags": false,

  "subTotal": 189.0,
  "grandTotal": 441.0,
  "totalExcludeControlledProducts": 441.0,
  "voucherDiscount": 0.0,
  "cartDiscount": 18.0,
  "shippingDiscount": 0.0,
  "bogoDiscount": 0.0,
  "expressShippingCost": 0.0,
  "totalDiscount": 18.0,
  "totalWeight": 0.5,
  "deliveryFee": 270.0,
  "discountedDeliveryFee": 270.0,
  "isFreeShipping": false,

  "validVouchers": [],
  "invalidVouchers": [],
  "discountResult": { "..." : "..." },
  "summary": { "..." : "..." }
}

Top-Level Computed Fields

Field Type Description
subTotal number Sum of price * quantity across all products (min 0)
grandTotal number Final order total after fees and discounts (min 0)
totalExcludeControlledProducts number Grand total excluding controlled products
voucherDiscount number Total discount from applied vouchers
cartDiscount number Total cart-level discount
shippingDiscount number Discount applied to delivery fee
bogoDiscount number Buy-one-get-one discount total
expressShippingCost number Express delivery surcharge
totalDiscount number Aggregate discount amount
totalWeight number Sum of product weights
deliveryFee number Raw delivery fee before discount
discountedDeliveryFee number Delivery fee after shipping discount (min 0)
isFreeShipping boolean Whether shipping is free

Passthrough Fields

Returned unchanged from the request:

basketName, basketId, branchId, orderId, orderDate, ownerId, requestSubstitute, specialComment, noPlasticBags

Nested Objects

Field Type Description
productList array[Product] Enriched product objects with computed prices
shipping Shipping Shipping object with calculated fees
validVouchers array Vouchers that were successfully applied
invalidVouchers array Vouchers that failed validation
discountResult object Detailed breakdown of coupon/discount results
summary TotalSummary Aggregated totals for the order

Product Object (Output)

Each product in the response includes all input fields plus computed fields.

{
  "cprcode": 146098,
  "productName": "ice cream",
  "quantity": 1,
  "scheduleId": 2,
  "isPreOrder": false,
  "originalPrice": 189.0,
  "price": 189.0,
  "rowTotal": 189.0,
  "discountedRowTotal": 189.0,
  "settlementPrice": 189.0,
  "weight": 0.5,
  "isControlledProduct": false
}
Field Type Description
cprcode integer Product code
productName string Display name
quantity integer Units ordered
scheduleId integer Linked schedule slot
isPreOrder boolean Pre-order flag
originalPrice number Price before any discount
price number Effective unit price
rowTotal number originalPrice * quantity
discountedRowTotal number price * quantity
settlementPrice number Settlement price from product master
weight number Product weight (kg)
isControlledProduct boolean Whether product is controlled

Grand Total Calculation

grandTotal = subTotal
           + discountedDeliveryFee
           + expressShippingCost
           - cartDiscount
           - bogoDiscount
           - voucherDiscount
           (max(0) guard applied)

discountedDeliveryFee = deliveryFee - shippingDiscount   (max(0) guard)
subTotal              = sum(product.price * product.quantity)   (max(0) guard)
deliveryFee           = sum(schedule.deliveryFee for schedule in calculated scheduleList)

two4Discount and percentageDiscount are computed but not subtracted from grandTotal. They may be folded into cartDiscount depending on the discount type.


Test Fixtures

Minimal and representative request bodies for testing:

File Description
test/testData/orderInput.yaml Minimal order with basic product list
test/testData/orderInput1.yaml Extended order with shipping and coupons
test/testData/noShipping.yaml Order with no shipping object

Error Handling

No structured error codes are defined. On any unhandled exception, the handler returns HTTP 500 with the error details in the response body. There is no fallback to resolve-coupon-master.