primary_item( $snapshot ); $draft = $snapshot->intent()->customer_draft() ?? []; $email = is_string( $draft['email'] ?? null ) ? (string) $draft['email'] : ''; if ( '' === $email ) { throw new DomainException( 'intent.incomplete', 'Customer email is required.' ); } $first = is_string( $draft['first_name'] ?? null ) ? (string) $draft['first_name'] : ''; if ( '' === trim( $first ) && is_string( $draft['name'] ?? null ) ) { $first = (string) $draft['name']; } if ( '' === trim( $first ) ) { throw new DomainException( 'intent.incomplete', 'Customer name is required.' ); } $last = is_string( $draft['last_name'] ?? null ) ? (string) $draft['last_name'] : null; $phone_raw = is_string( $draft['phone'] ?? null ) ? (string) $draft['phone'] : null; $notes = is_string( $draft['notes'] ?? null ) ? (string) $draft['notes'] : null; $tz_name = $item->timezone() ?? $snapshot->intent()->customer_timezone() ?? 'Europe/London'; $zone = new TimeZoneId( $tz_name ); $start = $item->start_utc(); $end = $item->end_utc(); if ( null === $start || null === $end ) { throw new DomainException( 'intent.incomplete', 'Booking slot is incomplete.' ); } $buf_s = $item->buffer_start_utc() ?? $start; $buf_e = $item->buffer_end_utc() ?? $end; $agent = $item->agent_id(); if ( null === $agent ) { $agents = $this->agents->find_active( 1, 0 ); if ( [] === $agents || null === $agents[0]->id() ) { throw new DomainException( 'intent.no_agent', 'No agent available for this booking.' ); } $agent = (int) $agents[0]->id(); } $phone = null; if ( null !== $phone_raw && '' !== trim( $phone_raw ) ) { $phone = new PhoneNumber( $phone_raw ); } $local = $start->setTimezone( $zone->to_date_time_zone() ); return new CreateBookingCommand( $item->service_id(), $item->duration_id(), $agent, $item->location_id(), $start, $end, $buf_s, $buf_e, $zone, $local, $item->attendees(), $item->price(), $first, $last, new EmailAddress( $email ), $phone, $notes, 0, true, ); } /** * First cart item with a scheduled slot. * * @param IntentSnapshot $snapshot Snapshot. * * @throws DomainException When no scheduled cart line exists. */ private function primary_item( IntentSnapshot $snapshot ): CartItem { foreach ( $snapshot->items() as $item ) { if ( null !== $item->start_utc() ) { return $item; } } throw new DomainException( 'intent.incomplete', 'Cart has no scheduled item.' ); } }