Skip to content

Migration Guide: calculatecost2 to calculatecost4

Import mapping, deleted modules, and validation procedure for migrating from the legacy src.calculateCost2 package to calculatecost4.


Import Mapping

Handler

Old import New import
src.calculateCost2.calculatecost2Lambda.calculatecost2Lambda calculatecost4.handler.calculatecost4Lambda

Core Models

Old import New import
src.calculateCost2.schema.order.Order calculatecost4.core.models.order.Order
src.calculateCost2.schema.product.Product calculatecost4.core.models.product.Product
src.calculateCost2.schema.shipping.* calculatecost4.core.models.shipping.*
src.calculateCost2.schema.voucher.Voucher calculatecost4.core.models.voucher.Voucher
src.calculateCost2.coupon.discount.* calculatecost4.core.models.discount.*

Adapters (DB and Service Calls)

Old import New import
src.calculateCost2.product.getPrice.* calculatecost4.adapters.dynamodb_pricing.*
src.calculateCost2.product.getProduct.* calculatecost4.adapters.dynamodb_product.*
src.calculateCost2.shipping.shippingCalculator.* calculatecost4.core.shipping_calc.*
src.calculateCost2.voucher.getVoucher.* calculatecost4.adapters.lambda_voucher.*
src.calculateCost2.coupon.couponCalculator.* calculatecost4.adapters.lambda_coupon.*

Deleted

Old import Status
src.calculateCost2.pipeThrough.* DELETED

What Was Deleted

pipeThrough.py

The pipeThrough module was an HTTP proxy that forwarded requests to the legacy calculatecost API endpoint. It existed as a fallback during the calculatecost2 migration period. In calculatecost4, the handler processes requests directly. There is no proxy layer.

resolve-coupon-master Fallback

The legacy handler had a fallback path that invoked resolve-coupon-master when the primary coupon Lambda failed. This fallback is removed. Coupon service failures now propagate as errors.


What Changed

DB Calls Moved from Model Properties to Injected Services

In calculatecost2, models made direct AWS calls from within their properties:

# Old: Product.price was a property that called DynamoDB
class Product:
    @property
    def price(self):
        return getPrice(self.cprcode, self.branchId)

In calculatecost4, models are plain data containers. AWS calls are made by adapter classes that implement Protocol interfaces. The handler wires adapters into the calculation pipeline at Lambda startup:

# New: Price is injected by the calculator
product.inject_price(pricing_service.get_price(cprcode, branch_id))

This separation enables: - Unit testing with mock services (no AWS credentials needed) - Swapping adapters (DynamoDB -> in-memory, Lambda -> local) - Clear dependency boundaries between core logic and infrastructure


Validation Procedure

Run the equivalence test to verify that calculatecost4 produces identical output to calculatecost2 for all test fixtures:

python -m pytest test/test_equivalence.py -v

The equivalence test: 1. Loads each YAML fixture from test/testData/ 2. Runs the fixture through both calculatecost2 and calculatecost4 handlers 3. Compares the response bodies field by field 4. Fails on any difference in computed fields (passthrough fields are excluded)

Fields compared:

Field Tolerance
grandTotal Exact
subTotal Exact
cartDiscount Exact
bogoDiscount Exact
deliveryFee Exact
voucherDiscount Exact
shippingDiscount Exact
expressShippingCost Exact
totalWeight Exact
discountedDeliveryFee Exact
Per-product price Exact
Per-product rowTotal Exact
Per-product weight Exact
Per-schedule deliveryFee Exact
Per-schedule expressFee Exact