Skip to content

calculatecost4 Data Models

Data model classes in calculatecost4/core/models/. Each class is a plain Python dataclass replacing the ad-hoc dict manipulation in the legacy src/calculateCost2/schema/ code.


Product

Module: core/models/product.py

Represents a single line item. Input fields come from the request; injected fields are set by the calculator after price lookup.

Input Fields

Field Type Required Default Notes
cprcode int Yes -- Product code; DynamoDB lookup key
productName str Yes -- Display name
quantity int Yes -- Units ordered
branchId str No "1000" Propagated from Order
scheduleId int No 0 Links to shipping schedule slot
isPreOrder bool No false Pre-order flag
remark str No "" Passthrough
discountFromCoupon float No 0 Coupon discount applied to this product
usedForCoupon str \| None No None Coupon code that claimed this product

Injected Fields (set by calculator)

Field Type Default Notes
_price float -- Current selling price from price table
_original_price float -- Original price before promotions
_weight float 0.25 Product weight in kg
_is_controlled bool -- Whether product is controlled (excluded from discounts)

Computed Properties

Property Return Type Computation
price float Returns _price
originalPrice float Returns _original_price
rowTotal float max(price * quantity, 0)
settlementPrice float Same as rowTotal
discountedRowTotal float max(rowTotal - discountFromCoupon, 0)
weight float Returns _weight
isControlledProduct bool Returns _is_controlled

Methods

Method Behaviour
clearDiscount() Sets discountFromCoupon = 0, usedForCoupon = None

Serialization: _asdict()

Returns:

{
    "cprcode": int,
    "productName": str,
    "quantity": int,
    "scheduleId": int,
    "isPreOrder": bool,
    "originalPrice": float,
    "price": float,
    "rowTotal": float,
    "discountedRowTotal": float,
    "settlementPrice": float,
    "weight": float,
    "isControlledProduct": bool,
}

Input-only fields (branchId, remark, discountFromCoupon, usedForCoupon) and injected fields (_price, _original_price, _weight, _is_controlled) are excluded from serialization output.


Order

Module: core/models/order.py

Top-level request container. Holds the product list, shipping info, and passthrough metadata fields.

Fields

Field Type Required Default Notes
productList list[Product] Yes -- Line items
voucherId list[str] No [] Voucher IDs to apply
basketName str No "" Passthrough
basketId str No "" Passthrough
branchId str No "1000" Propagated to all products
orderId str No "" Passthrough
orderDate float No 0 Unix timestamp
ownerId str No "" Used for voucher ownership checks
requestSubstitute bool No false Passthrough
specialComment str \| None No None Passthrough
noPlasticBags bool No false Passthrough
shipping Shipping \| None No None Delivery/pickup configuration
cartDiscountInfo list No [] Populated during discount calculation
couponCodeList list[str] No [] Coupon codes to validate and apply

Class Method: from_dict(input_dict)

Deserializes a raw request dict into an Order instance: 1. Filters input_dict keys to known field names (unknown keys are dropped). 2. Deserializes shipping value into a Shipping instance. 3. Deserializes each entry in productList into a Product instance. 4. Propagates branchId from Order to every Product in the list.

Method: to_dict()

Returns a flat dict containing: - All input fields - All computed totals (subTotal, grandTotal, etc.) - Nested productList serialized via Product._asdict() - Nested shipping serialized to dict


Shipping

Module: core/models/shipping.py

Delivery/pickup configuration attached to an Order.

Fields

Field Type Required Default Notes
scheduleList list[Schedule] No [] Delivery schedule slots
shippingType ShippingType No PICKUP DELIVERY or PICKUP
shippingPostcode str No "10110" Used for nationwide rate lookup
shippingLat float No 0 Latitude for Bangkok polygon check
shippingLon float No 0 Longitude for Bangkok polygon check
shippingFirstName str No "" Passthrough
shippingLastName str No "" Passthrough
shippingAddress str No "" Passthrough
shippingSubDistrict str No "" Passthrough
shippingProvince str No "" Passthrough
shippingPhone str No "" Passthrough
shippingEmail str No "" Passthrough
shippingDate float No 0 Unix timestamp; passthrough
shippingPrice float No 0 Total shipping price (computed)
weight float No 0 Total weight of shipment
brcode int No 1000 Branch code for polygon lookup

Schedule

Module: core/models/shipping.py

A single delivery schedule slot within a Shipping object.

Fields

Field Type Required Default Notes
mode ShippingMode No NATIONWIDE Determines fee calculator path
dateTime str Yes -- ISO-8601 timestamp
scheduleId int No 0 Links to Product.scheduleId
deliveryFee float No 0 Overwritten by fee calculation
pickingStatus str Yes -- Passthrough
date_slot str Yes -- Passthrough
booking_hour int No 0 Passthrough
expressFee int No 0 Overwritten; 50 THB if EXPRESS and first schedule
nationwideConfig str Yes -- Set to "none" for non-nationwide modes
nationwideMode NationwideMode No DRY Affects nationwide rate table lookup

Enums

Module: core/models/shipping.py

ShippingMode

Value Usage
NATIONWIDE Nationwide delivery; uses weight-based rate table
REGULAR Standard local delivery
EXPRESS Express delivery; adds 50 THB surcharge
PICKUP In-store pickup; zero delivery fee

ShippingType

Value Usage
DELIVERY Order is delivered to address
PICKUP Order is picked up in store

NationwideMode

Value Usage
FRESH Fresh/chilled products; higher shipping rate
DRY Dry goods; standard shipping rate
MIX Mixed fresh and dry; uses higher rate

NationwideCost

Module: core/models/shipping.py

A single row from the nationwide shipping rate table.

Fields

Field Type Required Default Notes
maxW float Yes -- Maximum weight threshold for this rate band
cost float Yes -- Shipping cost for this weight band
nationwideMode NationwideMode Yes -- Which mode this rate applies to

Voucher

Module: core/models/voucher.py

Represents a voucher (gift card / store credit) that can be applied to an order.

Fields

Field Type Required Default Notes
usedOnOwner str \| None No None Owner who used the voucher
usedOnOrder list No [] Orders this voucher was used on
isActive bool No true Whether voucher is active
isRefund bool No false Whether this is a refund voucher
ownerId str No "" Owner ID for ownership validation
voucherId str No "" Unique voucher identifier
value float No 0 Monetary value of voucher
creationDate float \| None No None Unix timestamp
useDate float \| None No None Unix timestamp

Computed Properties

Property Return Type Computation
isUsed bool len(usedOnOrder) > 0
isValid bool isActive AND NOT isUsed AND checkOwner()

Validation Methods

Method Behaviour
checkValidity() Returns false if isActive is false
checkUsage() Returns false if usedOnOrder is non-empty
checkOwner() Returns false if both usedOnOwner and ownerId are set and they differ

isValid is the composite check: all three validations must pass.


Discount

Module: core/models/discount.py

Result of applying a single coupon code. Each field tracks a different discount category.

Fields

Field Type Required Default Notes
coupon str Yes -- The coupon code that produced this discount
bogoDiscount float No 0 Buy-one-get-one discount amount
two4Discount float No 0 2-for-4 type promotion discount
discount float No 0 Flat cart-level discount
percentageDiscount float No 0 Percentage-based discount amount
freeshipping bool No false Whether this coupon grants free shipping
shippingDiscount float No 0 Discount applied to shipping fee

DiscountResult

Module: core/models/discount.py

Aggregated result of all coupon processing for an order.

Fields

Field Type Required Default Notes
discounts list[Discount] Yes -- Successfully applied discounts
failedCoupons list[str] Yes -- Coupon codes that failed validation
error dict Yes -- Error details (empty dict on success)

TotalSummary

Module: core/models/summary.py

Final computed totals for the order. Embedded in the response as the summary object.

Fields

Field Type Required Default Notes
subTotal float Yes -- Sum of all product.rowTotal
grandTotal float Yes -- Final order total after all adjustments
voucherDiscount float Yes -- Total voucher discount applied
cartDiscount float Yes -- Total flat coupon discount
bogoDiscount float Yes -- Total BOGO discount
two4Discount float Yes -- Total 2-for-4 discount
percentageDiscount float Yes -- Total percentage discount
shippingDiscount float Yes -- Total shipping discount
totalExcludeControlledProducts float Yes -- Grand total minus controlled product value
expressShippingCost float Yes -- Total express surcharges
deliveryFee float Yes -- Total delivery fee before discounts
discountedDeliveryFee float Yes -- max(deliveryFee - shippingDiscount, 0)
totalWeight float Yes -- Sum of all product.weight * quantity
discountResult dict Yes -- Serialized DiscountResult

Type Aliases

Module: core/models/types.py

Semantic type aliases for documentation clarity and type checking.

Alias Underlying Type Usage
Cprcode int Product code
Brcode int Branch code
CouponCode str Coupon code string
CouponId int Coupon database ID
Weight float Weight in kg
Lat float Latitude coordinate
Lon float Longitude coordinate
Cost float Monetary cost value
Postcode int Postal code

Model Dependency Graph

Order
 +-- productList: list[Product]
 +-- shipping: Shipping
      +-- scheduleList: list[Schedule]
      |    +-- mode: ShippingMode (enum)
      |    +-- nationwideMode: NationwideMode (enum)
      +-- shippingType: ShippingType (enum)

DiscountResult
 +-- discounts: list[Discount]

TotalSummary
 +-- discountResult: dict (serialized DiscountResult)

Voucher (standalone, looked up by voucherId)

NationwideCost (standalone, loaded from rate table)