diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/enrollments.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/enrollments.tsx index 7d81fd8..23023f0 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/enrollments.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/enrollments.tsx @@ -21,6 +21,11 @@ import { CardHeader, CardTitle } from '@repo/ui/components/ui/card' +import { + HoverCard, + HoverCardContent, + HoverCardTrigger +} from '@repo/ui/components/ui/hover-card' import { Popover, PopoverContent, @@ -54,8 +59,8 @@ export function Enrollments({ Matrículas relacionadas - Acompanhe o status e os detalhes de todas as matrículas relacionadas a - esta compra. + Acompanhe os detalhes de todas as matrículas relacionadas a esta + compra. @@ -64,18 +69,17 @@ export function Enrollments({ - - +
+ Colaborador Curso Status Executada em - {/*Agendada em*/} Revogada em - + {enrollments.map( ( { @@ -83,11 +87,13 @@ export function Enrollments({ course, status, executed_at, - // scheduled_at, - rollback_at + rollback_at, + reason: reason_ }, idx ) => { + const friendlyReason = reason_ ? reason(reason_) : null + return ( @@ -112,18 +118,28 @@ export function Enrollments({ {course.name} - + {friendlyReason ? ( + + + + + +

+ {' '} + {friendlyReason} +

+
+
+ ) : ( + + )}
{executed_at ? ( {executed_at} ) : null} - {/* - {scheduled_at ? ( - {scheduled_at} - ) : null} - */} + {rollback_at ? ( {rollback_at} @@ -140,6 +156,17 @@ export function Enrollments({ ) } +const reasons: Record = { + DEDUPLICATION: 'Matrícula ou agendamento já existentes.', + CANCELLATION: 'Cancelamento da matrícula.', + UNSCHEDULED: 'Cancelamento do agendamento da matrícula.', + DEADLINE: 'Data do agendamento é anterior ao dia atual.' +} as const + +const reason = (reason_: string): string | null => { + return reason_ in reasons ? reasons[reason_] : null +} + const statuses: Record = { PENDING: { icon: CircleDashedIcon, @@ -206,9 +233,9 @@ function SeatsMenu({ seats: seats_ }: { seats: Seat[] }) {
    - {seats.map(({ course, quantity }) => { + {seats.map(({ course, quantity }, idx) => { return ( -
  • +
  • {quantity}x {course.name}
  • ) diff --git a/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx b/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx index 7136e29..076bb22 100644 --- a/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx +++ b/apps/admin.saladeaula.digital/app/routes/_.$orgid.payments.$id._index/route.tsx @@ -110,6 +110,7 @@ type Item = { type User = { id: string name: string + email: string } type Invoice = { @@ -137,12 +138,13 @@ type Course = { } export type Enrollment = { - status: 'PENDING' | 'EXECUTED' | 'ROLLBACK' - user: { id: string; name: string; email: string } + status: 'PENDING' | 'EXECUTED' | 'ROLLBACK' | 'SCHEDULED' + user: User course: Course executed_at?: string rollback_at?: string scheduled_at?: string + reason?: string } export type Seat = { @@ -213,7 +215,7 @@ export default function Route({ loaderData: { order } }: Route.ComponentProps) { useEffect(() => { reset() }, []) - console.log(seats) + return (
    diff --git a/enrollments-events/app/events/restore_seat_on_scheduled_canceled.py b/enrollments-events/app/events/restore_seat_on_scheduled_canceled.py index ee03b5c..d780e2e 100644 --- a/enrollments-events/app/events/restore_seat_on_scheduled_canceled.py +++ b/enrollments-events/app/events/restore_seat_on_scheduled_canceled.py @@ -42,7 +42,7 @@ def lambda_handler(event: EventBridgeEvent, context: LambdaContext) -> bool: expr_attr_values={ ':rollback': 'ROLLBACK', ':scheduled': 'SCHEDULED', - ':reason': 'CANCELLATION', + ':reason': 'UNSCHEDULED', ':now': now_, }, table_name=ORDER_TABLE, diff --git a/orders-events/app/events/start_fulfillment.py b/orders-events/app/events/start_fulfillment.py index 3a4a81c..bc3b48f 100644 --- a/orders-events/app/events/start_fulfillment.py +++ b/orders-events/app/events/start_fulfillment.py @@ -19,7 +19,7 @@ from layercake.dynamodb import ( TransactKey, ) from layercake.strutils import md5_hash -from pydantic import UUID4, BaseModel, BeforeValidator, Field, FutureDate +from pydantic import UUID4, BaseModel, BeforeValidator, Field from boto3clients import dynamodb_client from config import ( @@ -42,6 +42,9 @@ class DeduplicationConflictError(Exception): ... class EnrollmentConflictError(Exception): ... +class DeadlineExceededError(Exception): ... + + class User(BaseModel): id: str name: str @@ -200,9 +203,12 @@ def _get_courses(ids: set[str]) -> tuple[Course, ...]: def _friendly_reason(reason: str) -> str: - if reason == 'DeduplicationConflictError': - return 'DEDUPLICATION' - return 'CONFLICT' + reasons = { + 'DeduplicationConflictError': 'DEDUPLICATION', + 'DeadlineExceededError': 'DEADLINE', + } + + return reasons.get(reason, 'CONFLICT') CreatedBy = TypedDict('CreatedBy', {'user_id': str, 'name': str}) @@ -341,6 +347,9 @@ def _enroll_later(enrollment: Enrollment, context: Context) -> None: scheduled_for = _date_to_midnight(enrollment.scheduled_for) # type: ignore lock_hash = md5_hash(f'{user.id}{course.id}') + if now_ > scheduled_for: + raise DeadlineExceededError('Deadline exceeded') + with dyn.transact_writer(table_name=ENROLLMENT_TABLE) as transact: pk = f'SCHEDULED#ORG#{org.id}' sk = f'{scheduled_for.isoformat()}#{lock_hash}'