from uuid import uuid4 from aws_lambda_powertools import Logger from aws_lambda_powertools.utilities.data_classes import ( EventBridgeEvent, event_source, ) from aws_lambda_powertools.utilities.typing import LambdaContext from layercake.dateutils import now from layercake.dynamodb import ( DynamoDBPersistenceLayer, KeyChain, KeyPair, SortKey, TransactKey, ) from boto3clients import dynamodb_client from config import COURSE_TABLE, ENROLLMENT_TABLE, ORDER_TABLE from enrollment import DeduplicationWindow, LinkedEntity, enroll from schemas import Course, Enrollment, User logger = Logger(__name__) order_layer = DynamoDBPersistenceLayer(ORDER_TABLE, dynamodb_client) course_layer = DynamoDBPersistenceLayer(COURSE_TABLE, dynamodb_client) enrollment_layer = DynamoDBPersistenceLayer(ENROLLMENT_TABLE, dynamodb_client) @event_source(data_class=EventBridgeEvent) @logger.inject_lambda_context def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> list[str]: new_image = event.detail['new_image'] now_ = now() order_id = new_image['id'] order = order_layer.collection.get_items( TransactKey(order_id) + SortKey('0') + SortKey('items', path_spec='items'), ) items = { item['id']: int(item['quantity']) for item in order['items'] # Ignore items with non-positive unit price; # negative values are treated as discounts if item['unit_price'] > 0 } courses = _get_courses(set(items.keys())) user = User( id=order['user_id'], name=order['name'], email=order['email'], cpf=order['cpf'], ) ids = [] for course in courses: enrollment = Enrollment( id=uuid4(), user=user, course=course, ) enroll( enrollment, persistence_layer=enrollment_layer, deduplication_window=DeduplicationWindow(offset_days=90), linked_entities=frozenset({LinkedEntity(order_id, 'ORDER')}), ) ids.append(str(enrollment.id)) order_layer.update_item( key=KeyPair(new_image['id'], new_image['sk']), update_expr='SET #status = :status, updated_at = :updated_at', expr_attr_names={ '#status': 'status', }, expr_attr_values={ ':status': 'SUCCESS', ':updated_at': now_, }, cond_expr='attribute_exists(sk)', ) return ids def _get_courses(ids: set) -> tuple[Course, ...]: pairs = tuple(KeyPair(idx, '0') for idx in ids) result = course_layer.collection.get_items( KeyChain(pairs), flatten_top=False, ) courses = tuple(Course(id=idx, **obj) for idx, obj in result.items()) # type: ignore return courses