ProcessUnpaidOrder Lambda Function
Quick Reference
- Function Name:
payment3-process-unpaid-order-${BRANCH} - Handler:
process_failed.lambda_handler - Runtime: Python 3.13 (Docker Image)
- Trigger: DynamoDB Stream (currently disabled)
- Timeout: 60 seconds (default)
- Template.yaml: Lines 917-962
Function Overview
The ProcessUnpaidOrder function processes failed/unpaid orders. It handles orders that have failed payment attempts, updates the order with failure status, sends failure notifications, and logs the processing attempt. Currently, the DynamoDB stream trigger is disabled in template.yaml.
Entry Point
File: functions/processPaidOrder/process_failed.py
Handler: lambda_handler(event, context)
def lambda_handler(event, context):
orderIds = getOrderFromEvent(event)
for orderId in orderIds:
processor = ProcessFailedOrder(orderId=orderId)
processor.save_failed_order()
processor.save_process_failed_order()
processor.send_failure_notifications()
return {"statusCode": 200, "body": json.dumps("success")}
Event Structure
DynamoDB Stream Event
Format: DynamoDB stream event (currently disabled)
Event Structure:
{
"Records": [
{
"eventName": "INSERT",
"dynamodb": {
"Keys": {
"orderId": {"S": "492500005643"}
}
}
}
]
}
Note: Only INSERT events are processed (new failed order records).
Core Classes
ProcessFailedOrder
Main processor class for handling failed orders.
Initialization:
processor = ProcessFailedOrder(orderId="492500005643")
Properties:
-
order(cached_property): Retrieves order from OrderTable@cached_property
def order(self) -> dict:
return OrderTable.get(self.orderId).data -
order_status(cached_property): Gets CheckStatusTable record@cached_property
def order_status(self) -> CheckStatusTable:
return next(CheckStatusTable.query(self.orderId)) -
payment_header(cached_property): Creates payment header with failure status@cached_property
def payment_header(self) -> dict:
return create_payment_header(
order=self.order,
paymentId=self.order_status.chargeId,
isPaid=False, # Always False for failed orders
paymentMethod=self.order_status.paymentMethod,
totalPaid=0 # No amount paid for failed orders
) -
failed_order(property): Order with failure payment header@property
def failed_order(self) -> dict:
order = self.order
order["payment"] = self.payment_header
return order
Methods:
save_failed_order(): Saves order with failure payment header to OrderTablesave_process_failed_order(): Logs processing attempt to ProcessUnpaidOrderTablesend_failure_notifications(): Sends failure notifications and email
DynamoDB Tables
OrderTable
Table Name: order-table-dev (shared)
Access Pattern: Get by orderId (hash key)
CheckStatusTable
Table Name: payment3-check-status-${BRANCH}
Access Pattern: Query by orderId (hash key)
Schema:
orderId(hash_key)created_at(range_key)chargeId: Charge identifierpaymentMethod: Payment methodstatus: Status string
ProcessUnpaidOrderTable
Table Name: payment3-process-unpaid-order-${BRANCH}
Access Pattern: Put item
Schema:
orderId(hash_key)created_at(range_key)data(JSON): Order data
Process Flow
- Receive DynamoDB Stream Event: Function receives stream event with failed order records
- Extract Order IDs: Get orderIds from INSERT events only
- Process Each Order:
- Initialize ProcessFailedOrder instance
- Retrieve order from OrderTable
- Get order status from CheckStatusTable
- Create payment header with
isPaid=False - Save failed order to OrderTable
- Log processing attempt to ProcessUnpaidOrderTable
- Send failure notifications and email
- Return Success: Return HTTP 200
Error Handling
- Order Not Found: Raises exception if order doesn't exist in OrderTable
- CheckStatus Not Found: Raises
CheckStatusNotFoundif status record doesn't exist - Notification Errors: Exceptions are caught and logged, then re-raised
- Continue on Error: If one order fails, processing continues with next order
Lambda Invocations
Invoked Functions
use-voucher-master: For voucher/coupon handling (if applicable)record-usage-coupon2-master: For coupon usage recording (if applicable)payment3-check-status-${BRANCH}: For status verification (if applicable)Pay: For order processing (if applicable)
Invoked By
- DynamoDB Stream (currently disabled in template.yaml)
IAM Policies
Required Permissions:
DynamoDBReadPolicyonCardPaymentRecordTableDynamoDBReadPolicyonCheckStatusTableDynamoDBCrudPolicyonProcessUnpaidOrderTableDynamoDBReadPolicyonorder-table-devDynamoDBCrudPolicyonEmailLogTableLambdaInvokePolicyonuse-voucher-masterLambdaInvokePolicyonrecord-usage-coupon2-masterLambdaInvokePolicyonpayment3-check-status-${BRANCH}LambdaInvokePolicyonPayfunctionSESCrudPolicyon*SNS:Publishon*
Environment Variables
BRANCH: Deployment branch name (default: "dev")
Dependencies
src.tables.*: DynamoDB table modelssrc.updatePaymentHeader: Payment header creationsrc.savePaidOrder: Order saving logicsrc.notifications.notify.notifyFailure: Failure notification sendingsrc.notifications.sendEmail.send_email: Email sending
Helper Functions
getOrderFromEvent
Extracts order IDs from DynamoDB stream events:
def getOrderFromEvent(event, *args):
records: list[dict] = event["Records"]
orderFromRecord = lambda record: record["dynamodb"]["Keys"]["orderId"]["S"]
orderIds: list[str] = [
orderFromRecord(record)
for record in records
if record["eventName"] == "INSERT"
]
return orderIds
Related Functions
ProcessPaidOrder: Processes successfully paid ordersProcessPaidOrderInternal: Processes paid orders (QR/Card)CheckStatus: Checks payment status
Notes
- This function handles failed/unpaid orders only
- Payment header always has
isPaid=FalseandtotalPaid=0 - DynamoDB stream trigger is currently disabled in template.yaml
- Only processes
INSERTevents from the stream - Sends failure notifications via SNS and email via SES
- Email is sent to
order.emailfield