from http import HTTPStatus from typing import Annotated from aws_lambda_powertools.event_handler.api_gateway import Router from aws_lambda_powertools.event_handler.exceptions import NotFoundError from aws_lambda_powertools.event_handler.openapi.params import Body from layercake.dateutils import now, ttl from layercake.dynamodb import ( DynamoDBPersistenceLayer, KeyPair, ) from layercake.extra_types import CreditCard from pydantic import UUID4 from api_gateway import JSONResponse from boto3clients import dynamodb_client from config import ORDER_TABLE from exceptions import OrderConflictError router = Router() dyn = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client) class InvoiceNotFoundError(NotFoundError): ... @router.post('//payment-retries') def payment_retries( order_id: str, credit_card: Annotated[CreditCard, Body(embed=True)], invoice_id: Annotated[UUID4 | str, Body(embed=True)], installments: Annotated[int, Body(embed=True)], ): now_ = now() with dyn.transact_writer() as transact: transact.condition( key=KeyPair(order_id, '0'), cond_expr='attribute_exists(sk) \ AND installments = :installments \ AND #status = :pending', expr_attr_names={ '#status': 'status', }, expr_attr_values={ ':pending': 'PENDING', ':installments': installments, }, exc_cls=OrderConflictError, ) transact.condition( key=KeyPair(order_id, 'INVOICE'), cond_expr='attribute_exists(sk) AND invoice_id = :invoice_id', expr_attr_values={ ':invoice_id': invoice_id, }, exc_cls=InvoiceNotFoundError, ) transact.put( item={ 'id': order_id, 'sk': 'CREDIT_CARD', 'brand': credit_card.brand, 'last4': credit_card.last4, 'created_at': now_, } ) transact.put( item={ 'id': order_id, 'sk': 'TRANSACTION', 'invoice_id': invoice_id, 'credit_card': credit_card.model_dump(), 'installments': installments, 'ttl': ttl(start_dt=now_, minutes=5), 'created_at': now_, }, cond_expr='attribute_not_exists(sk)', ) transact.update( key=KeyPair(order_id, 'TRANSACTION#STATS'), update_expr='SET updated_at = :now REMOVE last_attempt_succeeded', expr_attr_values={ ':now': now(), }, cond_expr='attribute_exists(sk)', ) return JSONResponse(status_code=HTTPStatus.CREATED)