finish seat

This commit is contained in:
2026-01-25 04:52:44 -03:00
parent 5fac7888a8
commit 3719842ae9
31 changed files with 731 additions and 134 deletions

View File

@@ -19,9 +19,16 @@ from layercake.strutils import md5_hash
from pydantic import UUID4, BaseModel, EmailStr, Field, FutureDate
from boto3clients import dynamodb_client
from config import DEDUP_WINDOW_OFFSET_DAYS, ENROLLMENT_TABLE, TZ, USER_TABLE
from config import (
DEDUP_WINDOW_OFFSET_DAYS,
ENROLLMENT_TABLE,
ORDER_TABLE,
TZ,
USER_TABLE,
)
from exceptions import (
ConflictError,
OrderNotFoundError,
SubscriptionConflictError,
SubscriptionFrozenError,
SubscriptionRequiredError,
@@ -62,20 +69,7 @@ class Subscription(BaseModel):
class Seat(BaseModel):
id: str = Field(..., pattern=r'^SEAT#ORG#.+$')
sk: str = Field(..., pattern=r'^ORDER#.+#ENROLLMENT#.+$')
def org_id(self) -> str:
*_, org_id = self.id.split('#')
return org_id
def order_id(self) -> str:
_, order_id, *_ = self.sk.split('#')
return order_id
def enrollment_id(self) -> str:
*_, enrollment_id = self.sk.split('#')
return enrollment_id
order_id: UUID4
class Enrollment(BaseModel):
@@ -166,9 +160,9 @@ def enroll_now(enrollment: Enrollment, context: Context):
user = enrollment.user
course = enrollment.course
seat = enrollment.seat
org: Org = context['org']
subscription: Subscription | None = context.get('subscription')
created_by: Authenticated = context['created_by']
org = context['org']
subscription = context.get('subscription')
created_by = context['created_by']
lock_hash = md5_hash(f'{user.id}{course.id}')
access_expires_at = now_ + timedelta(days=course.access_period)
deduplication_window = enrollment.deduplication_window
@@ -182,7 +176,7 @@ def enroll_now(enrollment: Enrollment, context: Context):
days=course.access_period - offset_days,
)
if not subscription and not seat:
if not (bool(subscription) ^ bool(seat)):
raise BadRequestError('Malformed body')
with dyn.transact_writer() as transact:
@@ -220,8 +214,29 @@ def enroll_now(enrollment: Enrollment, context: Context):
)
if seat:
transact.condition(
key=KeyPair(str(seat.order_id), '0'),
cond_expr='attribute_exists(sk)',
exc_cls=OrderNotFoundError,
table_name=ORDER_TABLE,
)
transact.put(
item={
'id': seat.order_id,
'sk': f'ENROLLMENT#{enrollment.id}',
'course': course.model_dump(),
'user': user.model_dump(),
'status': 'EXECUTED',
'executed_at': now_,
'created_at': now_,
},
table_name=ORDER_TABLE,
)
transact.delete(
key=KeyPair(seat.id, seat.sk),
key=KeyPair(
f'SEAT#ORG#{org.id}',
f'ORDER#{seat.order_id}#ENROLLMENT#{enrollment.id}',
),
cond_expr='attribute_exists(sk)',
exc_cls=SeatNotFoundError,
)
@@ -307,14 +322,14 @@ def enroll_later(enrollment: Enrollment, context: Context):
user = enrollment.user
course = enrollment.course
seat = enrollment.seat
scheduled_for = date_to_midnight(enrollment.scheduled_for) # type: ignore
scheduled_for = _date_to_midnight(enrollment.scheduled_for) # type: ignore
dedup_window = enrollment.deduplication_window
org: Org = context['org']
subscription: Subscription | None = context.get('subscription')
created_by: Authenticated = context['created_by']
org = context['org']
subscription = context.get('subscription')
created_by = context['created_by']
lock_hash = md5_hash(f'{user.id}{course.id}')
if not subscription and not seat:
if not (bool(subscription) ^ bool(seat)):
raise BadRequestError('Malformed body')
with dyn.transact_writer() as transact:
@@ -349,6 +364,35 @@ def enroll_later(enrollment: Enrollment, context: Context):
else {}
),
)
if seat:
transact.condition(
key=KeyPair(str(seat.order_id), '0'),
cond_expr='attribute_exists(sk)',
exc_cls=OrderNotFoundError,
table_name=ORDER_TABLE,
)
transact.put(
item={
'id': seat.order_id,
'sk': f'ENROLLMENT#{enrollment.id}',
'user': user.model_dump(),
'course': course.model_dump(),
'status': 'SCHEDULED',
'scheduled_at': now_,
'created_at': now_,
},
table_name=ORDER_TABLE,
)
transact.delete(
key=KeyPair(
f'SEAT#ORG#{org.id}',
f'ORDER#{seat.order_id}#ENROLLMENT#{enrollment.id}',
),
cond_expr='attribute_exists(sk)',
exc_cls=SeatNotFoundError,
)
transact.put(
item={
'id': 'LOCK#SCHEDULED',
@@ -387,15 +431,8 @@ def enroll_later(enrollment: Enrollment, context: Context):
table_name=USER_TABLE,
)
if seat:
transact.delete(
key=KeyPair(seat.id, seat.sk),
cond_expr='attribute_exists(sk)',
exc_cls=SeatNotFoundError,
)
return enrollment
def date_to_midnight(dt: date) -> datetime:
def _date_to_midnight(dt: date) -> datetime:
return datetime.combine(dt, time(0, 0)).replace(tzinfo=pytz.timezone(TZ))