wxcli 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wxcli/__init__.py +4 -0
- wxcli/_playbook/.claude/agents/migration-advisor.md +239 -0
- wxcli/_playbook/.claude/agents/wxc-calling-builder.md +946 -0
- wxcli/_playbook/.claude/rules/cleanup.md +29 -0
- wxcli/_playbook/.claude/rules/cucm-migration.md +58 -0
- wxcli/_playbook/.claude/rules/org-health.md +14 -0
- wxcli/_playbook/.claude/settings.json +8 -0
- wxcli/_playbook/.claude/skills/audit-compliance/SKILL.md +515 -0
- wxcli/_playbook/.claude/skills/call-control/SKILL.md +747 -0
- wxcli/_playbook/.claude/skills/configure-features/SKILL.md +623 -0
- wxcli/_playbook/.claude/skills/configure-routing/SKILL.md +627 -0
- wxcli/_playbook/.claude/skills/contact-center/SKILL.md +1181 -0
- wxcli/_playbook/.claude/skills/cucm-migrate/SKILL.md +820 -0
- wxcli/_playbook/.claude/skills/customer-assist/SKILL.md +443 -0
- wxcli/_playbook/.claude/skills/device-platform/SKILL.md +407 -0
- wxcli/_playbook/.claude/skills/manage-call-settings/SKILL.md +757 -0
- wxcli/_playbook/.claude/skills/manage-devices/SKILL.md +790 -0
- wxcli/_playbook/.claude/skills/manage-identity/SKILL.md +638 -0
- wxcli/_playbook/.claude/skills/manage-licensing/SKILL.md +528 -0
- wxcli/_playbook/.claude/skills/manage-meetings/SKILL.md +708 -0
- wxcli/_playbook/.claude/skills/messaging-bots/SKILL.md +365 -0
- wxcli/_playbook/.claude/skills/messaging-spaces/SKILL.md +520 -0
- wxcli/_playbook/.claude/skills/org-health/SKILL.md +159 -0
- wxcli/_playbook/.claude/skills/provision-calling/SKILL.md +421 -0
- wxcli/_playbook/.claude/skills/query-live/SKILL.md +183 -0
- wxcli/_playbook/.claude/skills/query-live/domains/call-flow-trace.md +223 -0
- wxcli/_playbook/.claude/skills/query-live/domains/call-history.md +44 -0
- wxcli/_playbook/.claude/skills/query-live/domains/features.md +169 -0
- wxcli/_playbook/.claude/skills/query-live/domains/numbers.md +93 -0
- wxcli/_playbook/.claude/skills/query-live/domains/people-and-settings.md +146 -0
- wxcli/_playbook/.claude/skills/query-live/domains/routing.md +124 -0
- wxcli/_playbook/.claude/skills/reporting/SKILL.md +501 -0
- wxcli/_playbook/.claude/skills/reporting/references/cdr-recipes.md +1628 -0
- wxcli/_playbook/.claude/skills/reporting-cc/SKILL.md +251 -0
- wxcli/_playbook/.claude/skills/reporting-meetings/SKILL.md +290 -0
- wxcli/_playbook/.claude/skills/teardown/SKILL.md +214 -0
- wxcli/_playbook/.claude/skills/video-mesh/SKILL.md +379 -0
- wxcli/_playbook/.claude/skills/wxc-calling-debug/SKILL.md +475 -0
- wxcli/_playbook/CLAUDE.md +373 -0
- wxcli/_playbook/docs/reference/CLAUDE.md +25 -0
- wxcli/_playbook/docs/reference/admin-apps-data.md +643 -0
- wxcli/_playbook/docs/reference/admin-audit-security.md +322 -0
- wxcli/_playbook/docs/reference/admin-hybrid.md +383 -0
- wxcli/_playbook/docs/reference/admin-identity-scim.md +1007 -0
- wxcli/_playbook/docs/reference/admin-licensing.md +414 -0
- wxcli/_playbook/docs/reference/admin-org-management.md +586 -0
- wxcli/_playbook/docs/reference/admin-partner.md +357 -0
- wxcli/_playbook/docs/reference/archive/wxc-sdk-patterns.md +1229 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-advanced.md +835 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-core.md +743 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-devices-workspaces.md +1305 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-features.md +849 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-locations.md +938 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-person.md +1255 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-routing.md +1262 -0
- wxcli/_playbook/docs/reference/authentication.md +965 -0
- wxcli/_playbook/docs/reference/call-control.md +1205 -0
- wxcli/_playbook/docs/reference/call-features-additional.md +2541 -0
- wxcli/_playbook/docs/reference/call-features-major.md +1320 -0
- wxcli/_playbook/docs/reference/call-routing.md +2304 -0
- wxcli/_playbook/docs/reference/contact-center-analytics.md +1049 -0
- wxcli/_playbook/docs/reference/contact-center-core.md +1614 -0
- wxcli/_playbook/docs/reference/contact-center-journey.md +457 -0
- wxcli/_playbook/docs/reference/contact-center-routing.md +1138 -0
- wxcli/_playbook/docs/reference/devices-core.md +1869 -0
- wxcli/_playbook/docs/reference/devices-dect.md +1150 -0
- wxcli/_playbook/docs/reference/devices-platform.md +467 -0
- wxcli/_playbook/docs/reference/devices-workspaces.md +1426 -0
- wxcli/_playbook/docs/reference/emergency-services.md +1122 -0
- wxcli/_playbook/docs/reference/location-calling-core.md +2037 -0
- wxcli/_playbook/docs/reference/location-calling-media.md +1334 -0
- wxcli/_playbook/docs/reference/location-recording-advanced.md +1482 -0
- wxcli/_playbook/docs/reference/meetings-content.md +473 -0
- wxcli/_playbook/docs/reference/meetings-core.md +903 -0
- wxcli/_playbook/docs/reference/meetings-infrastructure.md +899 -0
- wxcli/_playbook/docs/reference/meetings-settings.md +850 -0
- wxcli/_playbook/docs/reference/messaging-bots.md +1091 -0
- wxcli/_playbook/docs/reference/messaging-spaces.md +695 -0
- wxcli/_playbook/docs/reference/person-call-settings-behavior.md +1639 -0
- wxcli/_playbook/docs/reference/person-call-settings-handling.md +1394 -0
- wxcli/_playbook/docs/reference/person-call-settings-media.md +1898 -0
- wxcli/_playbook/docs/reference/person-call-settings-permissions.md +1329 -0
- wxcli/_playbook/docs/reference/provisioning.md +1366 -0
- wxcli/_playbook/docs/reference/reporting-analytics.md +1318 -0
- wxcli/_playbook/docs/reference/self-service-call-settings.md +1020 -0
- wxcli/_playbook/docs/reference/virtual-lines.md +1132 -0
- wxcli/_playbook/docs/reference/webhooks-events.md +1444 -0
- wxcli/_playbook/docs/reference/wxcadm-xsi-realtime.md +953 -0
- wxcli/_version.py +24 -0
- wxcli/auth.py +137 -0
- wxcli/commands/__init__.py +0 -0
- wxcli/commands/_registry.py +181 -0
- wxcli/commands/activation_email.py +103 -0
- wxcli/commands/admin_recordings.py +585 -0
- wxcli/commands/analytics.py +105 -0
- wxcli/commands/announcement_playlists.py +219 -0
- wxcli/commands/announcements.py +519 -0
- wxcli/commands/archive_users.py +36 -0
- wxcli/commands/attachment_actions.py +60 -0
- wxcli/commands/audit_events.py +83 -0
- wxcli/commands/authorizations.py +113 -0
- wxcli/commands/auto_attendant.py +642 -0
- wxcli/commands/broadworks_billing_reports.py +126 -0
- wxcli/commands/broadworks_enterprises.py +160 -0
- wxcli/commands/broadworks_subscribers.py +319 -0
- wxcli/commands/broadworks_workspaces.py +108 -0
- wxcli/commands/call_controls.py +1304 -0
- wxcli/commands/call_park.py +494 -0
- wxcli/commands/call_pickup.py +229 -0
- wxcli/commands/call_queue.py +1878 -0
- wxcli/commands/call_recording.py +707 -0
- wxcli/commands/call_routing.py +1610 -0
- wxcli/commands/call_settings_for_me_phase_5.py +212 -0
- wxcli/commands/caller_reputation.py +169 -0
- wxcli/commands/calling_service.py +305 -0
- wxcli/commands/cc_address_book.py +770 -0
- wxcli/commands/cc_agent_greetings.py +242 -0
- wxcli/commands/cc_agent_summaries.py +39 -0
- wxcli/commands/cc_agent_wellbeing.py +216 -0
- wxcli/commands/cc_agents.py +425 -0
- wxcli/commands/cc_ai_assistant.py +55 -0
- wxcli/commands/cc_ai_feature.py +294 -0
- wxcli/commands/cc_audio_files.py +149 -0
- wxcli/commands/cc_auto_csat.py +311 -0
- wxcli/commands/cc_aux_code.py +458 -0
- wxcli/commands/cc_business_hour.py +353 -0
- wxcli/commands/cc_call_monitoring.py +228 -0
- wxcli/commands/cc_callbacks.py +194 -0
- wxcli/commands/cc_campaign.py +212 -0
- wxcli/commands/cc_captures.py +39 -0
- wxcli/commands/cc_contact_list.py +169 -0
- wxcli/commands/cc_contact_number.py +295 -0
- wxcli/commands/cc_data_sources.py +235 -0
- wxcli/commands/cc_desktop_layout.py +380 -0
- wxcli/commands/cc_desktop_profile.py +322 -0
- wxcli/commands/cc_dial_number.py +511 -0
- wxcli/commands/cc_dial_plan.py +347 -0
- wxcli/commands/cc_dnc.py +101 -0
- wxcli/commands/cc_entry_point.py +545 -0
- wxcli/commands/cc_ewt.py +51 -0
- wxcli/commands/cc_flow.py +477 -0
- wxcli/commands/cc_global_vars.py +430 -0
- wxcli/commands/cc_holiday_list.py +335 -0
- wxcli/commands/cc_journey.py +1261 -0
- wxcli/commands/cc_legacy_flows.py +49 -0
- wxcli/commands/cc_multimedia_profile.py +436 -0
- wxcli/commands/cc_notification.py +51 -0
- wxcli/commands/cc_outdial_ani.py +604 -0
- wxcli/commands/cc_overrides.py +341 -0
- wxcli/commands/cc_queue.py +1083 -0
- wxcli/commands/cc_queue_stats.py +55 -0
- wxcli/commands/cc_realtime.py +51 -0
- wxcli/commands/cc_resource_collection.py +312 -0
- wxcli/commands/cc_search.py +46 -0
- wxcli/commands/cc_site.py +400 -0
- wxcli/commands/cc_skill.py +350 -0
- wxcli/commands/cc_skill_profile.py +289 -0
- wxcli/commands/cc_subscriptions.py +426 -0
- wxcli/commands/cc_summaries.py +130 -0
- wxcli/commands/cc_tasks.py +844 -0
- wxcli/commands/cc_team.py +325 -0
- wxcli/commands/cc_user_profiles.py +349 -0
- wxcli/commands/cc_users.py +701 -0
- wxcli/commands/cc_work_types.py +363 -0
- wxcli/commands/cdr.py +89 -0
- wxcli/commands/classifications.py +38 -0
- wxcli/commands/cleanup.py +1427 -0
- wxcli/commands/client_settings.py +72 -0
- wxcli/commands/conference.py +328 -0
- wxcli/commands/configure.py +72 -0
- wxcli/commands/converged_recordings.py +347 -0
- wxcli/commands/converged_recordings_export.py +310 -0
- wxcli/commands/cq_playlists.py +42 -0
- wxcli/commands/cucm.py +2794 -0
- wxcli/commands/cucm_config.py +129 -0
- wxcli/commands/customer_assist.py +373 -0
- wxcli/commands/data_sources.py +227 -0
- wxcli/commands/dect_devices.py +787 -0
- wxcli/commands/device_configurations.py +77 -0
- wxcli/commands/device_dynamic_settings.py +320 -0
- wxcli/commands/device_settings.py +1489 -0
- wxcli/commands/devices.py +280 -0
- wxcli/commands/domains.py +142 -0
- wxcli/commands/ecm.py +178 -0
- wxcli/commands/emergency_services.py +827 -0
- wxcli/commands/events.py +83 -0
- wxcli/commands/external_voicemail.py +52 -0
- wxcli/commands/groups.py +206 -0
- wxcli/commands/guest_management.py +76 -0
- wxcli/commands/hds.py +340 -0
- wxcli/commands/hot_desk.py +67 -0
- wxcli/commands/hot_desking_members.py +118 -0
- wxcli/commands/hot_desking_portal.py +124 -0
- wxcli/commands/hunt_group.py +577 -0
- wxcli/commands/hybrid_clusters.py +71 -0
- wxcli/commands/hybrid_connectors.py +67 -0
- wxcli/commands/identity_org.py +159 -0
- wxcli/commands/init_playbook.py +155 -0
- wxcli/commands/licenses.py +106 -0
- wxcli/commands/live_monitoring.py +40 -0
- wxcli/commands/location_call_handling.py +577 -0
- wxcli/commands/location_schedules.py +341 -0
- wxcli/commands/location_settings.py +1297 -0
- wxcli/commands/location_voicemail.py +494 -0
- wxcli/commands/locations.py +336 -0
- wxcli/commands/meeting_captions.py +110 -0
- wxcli/commands/meeting_chats.py +63 -0
- wxcli/commands/meeting_invitees.py +234 -0
- wxcli/commands/meeting_messages.py +28 -0
- wxcli/commands/meeting_participants.py +278 -0
- wxcli/commands/meeting_polls.py +111 -0
- wxcli/commands/meeting_preferences.py +515 -0
- wxcli/commands/meeting_qa.py +78 -0
- wxcli/commands/meeting_qualities.py +43 -0
- wxcli/commands/meeting_reports.py +101 -0
- wxcli/commands/meeting_session_types.py +105 -0
- wxcli/commands/meeting_site.py +57 -0
- wxcli/commands/meeting_slido.py +44 -0
- wxcli/commands/meeting_summaries.py +92 -0
- wxcli/commands/meeting_tracking_codes.py +233 -0
- wxcli/commands/meeting_transcripts.py +230 -0
- wxcli/commands/meetings.py +1997 -0
- wxcli/commands/memberships.py +164 -0
- wxcli/commands/messages.py +213 -0
- wxcli/commands/mode_management.py +244 -0
- wxcli/commands/my_call_settings.py +3577 -0
- wxcli/commands/numbers.py +405 -0
- wxcli/commands/operating_modes.py +410 -0
- wxcli/commands/org_contacts.py +284 -0
- wxcli/commands/org_health_cli.py +55 -0
- wxcli/commands/org_settings.py +71 -0
- wxcli/commands/organizations.py +83 -0
- wxcli/commands/paging_group.py +257 -0
- wxcli/commands/partner_admins.py +141 -0
- wxcli/commands/partner_reports.py +188 -0
- wxcli/commands/partner_tags.py +216 -0
- wxcli/commands/people.py +279 -0
- wxcli/commands/person_call_settings.py +71 -0
- wxcli/commands/pstn.py +280 -0
- wxcli/commands/recording_report.py +154 -0
- wxcli/commands/report_templates.py +38 -0
- wxcli/commands/reports.py +144 -0
- wxcli/commands/resource_group_memberships.py +160 -0
- wxcli/commands/resource_groups.py +67 -0
- wxcli/commands/roles.py +63 -0
- wxcli/commands/room_tabs.py +160 -0
- wxcli/commands/rooms.py +225 -0
- wxcli/commands/scim_bulk.py +46 -0
- wxcli/commands/scim_groups.py +246 -0
- wxcli/commands/scim_schemas.py +82 -0
- wxcli/commands/scim_users.py +283 -0
- wxcli/commands/security_audit.py +54 -0
- wxcli/commands/service_apps.py +51 -0
- wxcli/commands/single_number_reach.py +209 -0
- wxcli/commands/team_memberships.py +155 -0
- wxcli/commands/teams.py +153 -0
- wxcli/commands/ucm_profile.py +42 -0
- wxcli/commands/update.py +219 -0
- wxcli/commands/user_settings.py +5116 -0
- wxcli/commands/video_mesh.py +1090 -0
- wxcli/commands/virtual_extensions.py +502 -0
- wxcli/commands/virtual_line_settings.py +2072 -0
- wxcli/commands/webhooks.py +176 -0
- wxcli/commands/wholesale_billing_reports.py +147 -0
- wxcli/commands/wholesale_provisioning.py +523 -0
- wxcli/commands/workspace_locations.py +339 -0
- wxcli/commands/workspace_metrics.py +103 -0
- wxcli/commands/workspace_personalization.py +70 -0
- wxcli/commands/workspace_settings.py +3347 -0
- wxcli/commands/workspaces.py +279 -0
- wxcli/commands/xapi.py +114 -0
- wxcli/config.py +139 -0
- wxcli/errors.py +77 -0
- wxcli/main.py +210 -0
- wxcli/migration/CLAUDE.md +106 -0
- wxcli/migration/__init__.py +1 -0
- wxcli/migration/advisory/CLAUDE.md +196 -0
- wxcli/migration/advisory/__init__.py +46 -0
- wxcli/migration/advisory/advisor.py +107 -0
- wxcli/migration/advisory/advisory_patterns.py +2552 -0
- wxcli/migration/advisory/recommendation_rules.py +835 -0
- wxcli/migration/cucm/CLAUDE.md +74 -0
- wxcli/migration/cucm/__init__.py +5 -0
- wxcli/migration/cucm/connection.py +265 -0
- wxcli/migration/cucm/discovery.py +225 -0
- wxcli/migration/cucm/extractors/__init__.py +1 -0
- wxcli/migration/cucm/extractors/announcements.py +92 -0
- wxcli/migration/cucm/extractors/base.py +90 -0
- wxcli/migration/cucm/extractors/device_profiles.py +98 -0
- wxcli/migration/cucm/extractors/devices.py +193 -0
- wxcli/migration/cucm/extractors/e911.py +103 -0
- wxcli/migration/cucm/extractors/features.py +309 -0
- wxcli/migration/cucm/extractors/helpers.py +73 -0
- wxcli/migration/cucm/extractors/informational.py +295 -0
- wxcli/migration/cucm/extractors/locations.py +221 -0
- wxcli/migration/cucm/extractors/moh.py +100 -0
- wxcli/migration/cucm/extractors/remote_destinations.py +96 -0
- wxcli/migration/cucm/extractors/routing.py +493 -0
- wxcli/migration/cucm/extractors/shared_lines.py +146 -0
- wxcli/migration/cucm/extractors/templates.py +229 -0
- wxcli/migration/cucm/extractors/tier4.py +173 -0
- wxcli/migration/cucm/extractors/users.py +240 -0
- wxcli/migration/cucm/extractors/voicemail.py +243 -0
- wxcli/migration/cucm/extractors/workspaces.py +88 -0
- wxcli/migration/cucm/unity_connection.py +304 -0
- wxcli/migration/execute/CLAUDE.md +372 -0
- wxcli/migration/execute/__init__.py +303 -0
- wxcli/migration/execute/batch.py +277 -0
- wxcli/migration/execute/dependency.py +483 -0
- wxcli/migration/execute/engine.py +964 -0
- wxcli/migration/execute/handlers.py +2232 -0
- wxcli/migration/execute/planner.py +1939 -0
- wxcli/migration/execute/runtime.py +571 -0
- wxcli/migration/export/CLAUDE.md +49 -0
- wxcli/migration/export/__init__.py +8 -0
- wxcli/migration/export/csv_export.py +126 -0
- wxcli/migration/export/deployment_plan.py +479 -0
- wxcli/migration/export/json_export.py +60 -0
- wxcli/migration/models.py +941 -0
- wxcli/migration/phone_models.py +50 -0
- wxcli/migration/preflight/CLAUDE.md +52 -0
- wxcli/migration/preflight/__init__.py +89 -0
- wxcli/migration/preflight/checks.py +911 -0
- wxcli/migration/preflight/runner.py +293 -0
- wxcli/migration/rate_limiter.py +144 -0
- wxcli/migration/report/CLAUDE.md +245 -0
- wxcli/migration/report/__init__.py +7 -0
- wxcli/migration/report/appendix.py +2437 -0
- wxcli/migration/report/assembler.py +183 -0
- wxcli/migration/report/charts.py +263 -0
- wxcli/migration/report/executive.py +776 -0
- wxcli/migration/report/explainer.py +704 -0
- wxcli/migration/report/helpers.py +74 -0
- wxcli/migration/report/ingest.py +152 -0
- wxcli/migration/report/notice_templates.py +192 -0
- wxcli/migration/report/score.py +375 -0
- wxcli/migration/report/styles.py +1052 -0
- wxcli/migration/report/user_diff.py +1052 -0
- wxcli/migration/report/user_notice.py +425 -0
- wxcli/migration/state.py +139 -0
- wxcli/migration/store.py +860 -0
- wxcli/migration/transform/CLAUDE.md +107 -0
- wxcli/migration/transform/__init__.py +12 -0
- wxcli/migration/transform/analysis_pipeline.py +453 -0
- wxcli/migration/transform/analyzers/__init__.py +142 -0
- wxcli/migration/transform/analyzers/css_permission.py +189 -0
- wxcli/migration/transform/analyzers/css_routing.py +335 -0
- wxcli/migration/transform/analyzers/device_compatibility.py +122 -0
- wxcli/migration/transform/analyzers/dn_ambiguity.py +131 -0
- wxcli/migration/transform/analyzers/duplicate_user.py +221 -0
- wxcli/migration/transform/analyzers/extension_conflict.py +173 -0
- wxcli/migration/transform/analyzers/feature_approximation.py +227 -0
- wxcli/migration/transform/analyzers/layout_overflow.py +174 -0
- wxcli/migration/transform/analyzers/location_ambiguity.py +184 -0
- wxcli/migration/transform/analyzers/missing_data.py +300 -0
- wxcli/migration/transform/analyzers/selective_call_handling.py +394 -0
- wxcli/migration/transform/analyzers/shared_line.py +170 -0
- wxcli/migration/transform/analyzers/voicemail_compatibility.py +267 -0
- wxcli/migration/transform/analyzers/workspace_license.py +212 -0
- wxcli/migration/transform/cross_reference.py +1136 -0
- wxcli/migration/transform/cucm_pattern.py +246 -0
- wxcli/migration/transform/decisions.py +301 -0
- wxcli/migration/transform/e164.py +145 -0
- wxcli/migration/transform/engine.py +256 -0
- wxcli/migration/transform/mappers/CLAUDE.md +123 -0
- wxcli/migration/transform/mappers/__init__.py +76 -0
- wxcli/migration/transform/mappers/announcement_mapper.py +122 -0
- wxcli/migration/transform/mappers/base.py +190 -0
- wxcli/migration/transform/mappers/button_template_mapper.py +186 -0
- wxcli/migration/transform/mappers/call_forwarding_mapper.py +228 -0
- wxcli/migration/transform/mappers/call_settings_mapper.py +144 -0
- wxcli/migration/transform/mappers/css_mapper.py +868 -0
- wxcli/migration/transform/mappers/dect_mapper.py +367 -0
- wxcli/migration/transform/mappers/device_layout_mapper.py +289 -0
- wxcli/migration/transform/mappers/device_mapper.py +227 -0
- wxcli/migration/transform/mappers/device_profile_mapper.py +190 -0
- wxcli/migration/transform/mappers/device_settings_mapper.py +464 -0
- wxcli/migration/transform/mappers/e911_mapper.py +129 -0
- wxcli/migration/transform/mappers/ecbn_mapper.py +263 -0
- wxcli/migration/transform/mappers/executive_assistant_mapper.py +156 -0
- wxcli/migration/transform/mappers/feature_mapper.py +1179 -0
- wxcli/migration/transform/mappers/line_mapper.py +310 -0
- wxcli/migration/transform/mappers/location_mapper.py +235 -0
- wxcli/migration/transform/mappers/moh_mapper.py +114 -0
- wxcli/migration/transform/mappers/monitoring_mapper.py +221 -0
- wxcli/migration/transform/mappers/receptionist_mapper.py +245 -0
- wxcli/migration/transform/mappers/routing_mapper.py +821 -0
- wxcli/migration/transform/mappers/snr_mapper.py +201 -0
- wxcli/migration/transform/mappers/softkey_mapper.py +205 -0
- wxcli/migration/transform/mappers/user_mapper.py +264 -0
- wxcli/migration/transform/mappers/voicemail_group_mapper.py +286 -0
- wxcli/migration/transform/mappers/voicemail_mapper.py +514 -0
- wxcli/migration/transform/mappers/workspace_mapper.py +464 -0
- wxcli/migration/transform/normalizers.py +2008 -0
- wxcli/migration/transform/pattern_converter.py +106 -0
- wxcli/migration/transform/pipeline.py +271 -0
- wxcli/migration/transform/rules.py +255 -0
- wxcli/org_health/CLAUDE.md +63 -0
- wxcli/org_health/__init__.py +7 -0
- wxcli/org_health/analyze.py +93 -0
- wxcli/org_health/checks.py +458 -0
- wxcli/org_health/collector.py +62 -0
- wxcli/org_health/models.py +78 -0
- wxcli/org_health/report.py +300 -0
- wxcli/output.py +101 -0
- wxcli-1.2.0.dist-info/METADATA +505 -0
- wxcli-1.2.0.dist-info/RECORD +413 -0
- wxcli-1.2.0.dist-info/WHEEL +5 -0
- wxcli-1.2.0.dist-info/entry_points.txt +2 -0
- wxcli-1.2.0.dist-info/licenses/LICENSE +191 -0
- wxcli-1.2.0.dist-info/scm_file_list.json +751 -0
- wxcli-1.2.0.dist-info/scm_version.json +8 -0
- wxcli-1.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,941 @@
|
|
|
1
|
+
"""Canonical data models for CUCM-to-Webex migration.
|
|
2
|
+
|
|
3
|
+
All types use canonical field names only — no CUCM or Webex API field names.
|
|
4
|
+
Fields prefixed with cucm_ preserve CUCM-specific metadata for decision context.
|
|
5
|
+
|
|
6
|
+
Sources:
|
|
7
|
+
- MigrationStatus, Provenance, MigrationObject: cucm-wxc-migration.md lines 113-143
|
|
8
|
+
- Concrete types: cucm-wxc-migration.md lines 145-153
|
|
9
|
+
- Field details: 03b-transform-mappers.md mapper field tables
|
|
10
|
+
- Object status progression: 07-idempotency-resumability.md lines 149-160
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from enum import Enum
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from pydantic import BaseModel, Field
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
# Enums
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
class MigrationStatus(str, Enum):
|
|
27
|
+
"""Object-level migration status.
|
|
28
|
+
|
|
29
|
+
Four-state progression for analysis: discovered -> normalized -> analyzed -> planned
|
|
30
|
+
Full lifecycle includes execution states.
|
|
31
|
+
(from cucm-wxc-migration.md lines 113-123, 07-idempotency-resumability.md lines 149-160)
|
|
32
|
+
"""
|
|
33
|
+
DISCOVERED = "discovered"
|
|
34
|
+
NORMALIZED = "normalized" # (from 07-idempotency-resumability.md line 158)
|
|
35
|
+
ANALYZED = "analyzed"
|
|
36
|
+
NEEDS_DECISION = "needs_decision"
|
|
37
|
+
PLANNED = "planned"
|
|
38
|
+
PREFLIGHT_PASSED = "preflight_passed"
|
|
39
|
+
EXECUTING = "executing"
|
|
40
|
+
COMPLETED = "completed"
|
|
41
|
+
FAILED = "failed"
|
|
42
|
+
SKIPPED = "skipped"
|
|
43
|
+
ROLLED_BACK = "rolled_back"
|
|
44
|
+
STALE = "stale" # (from 07-idempotency-resumability.md line 179)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class OpStatus(str, Enum):
|
|
48
|
+
"""Canonical execution-op status (plan_operations.status).
|
|
49
|
+
|
|
50
|
+
Mirrors the existing raw-string literals used across runtime.py, engine.py,
|
|
51
|
+
and store queries — this enum is the single source of truth going forward.
|
|
52
|
+
Existing raw-string call sites do not need migration because the string
|
|
53
|
+
values are identical; only new code should reference ``OpStatus.X.value``.
|
|
54
|
+
"""
|
|
55
|
+
PENDING = "pending"
|
|
56
|
+
IN_PROGRESS = "in_progress"
|
|
57
|
+
COMPLETED = "completed"
|
|
58
|
+
SKIPPED = "skipped"
|
|
59
|
+
FAILED = "failed"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class LineClassification(str, Enum):
|
|
63
|
+
"""DN classification result from E.164 normalization algorithm.
|
|
64
|
+
(from 03b-transform-mappers.md, line_mapper E.164 algorithm lines 208-211)
|
|
65
|
+
"""
|
|
66
|
+
EXTENSION = "EXTENSION"
|
|
67
|
+
NATIONAL = "NATIONAL"
|
|
68
|
+
E164 = "E164"
|
|
69
|
+
AMBIGUOUS = "AMBIGUOUS"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class DeviceCompatibilityTier(str, Enum):
|
|
73
|
+
"""Six-tier device model compatibility classification.
|
|
74
|
+
(from 03b-transform-mappers.md, device_mapper compatibility table lines 270-274)
|
|
75
|
+
"""
|
|
76
|
+
NATIVE_MPP = "native_mpp"
|
|
77
|
+
CONVERTIBLE = "convertible"
|
|
78
|
+
WEBEX_APP = "webex_app"
|
|
79
|
+
INFRASTRUCTURE = "infrastructure"
|
|
80
|
+
INCOMPATIBLE = "incompatible"
|
|
81
|
+
DECT = "dect"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class DecisionType(str, Enum):
|
|
85
|
+
"""Types of migration decisions requiring user input.
|
|
86
|
+
(from 03b-transform-mappers.md, all mapper decision tables)
|
|
87
|
+
(from 03-conflict-detection-engine.md, analyzer decision tables)
|
|
88
|
+
"""
|
|
89
|
+
EXTENSION_CONFLICT = "EXTENSION_CONFLICT"
|
|
90
|
+
DN_AMBIGUOUS = "DN_AMBIGUOUS"
|
|
91
|
+
DEVICE_INCOMPATIBLE = "DEVICE_INCOMPATIBLE"
|
|
92
|
+
# DEPRECATED 2026-04-15: convertibility is now a device classification
|
|
93
|
+
# (tier='convertible'), not an operator choice. The planner emits the
|
|
94
|
+
# create_activation_code op unconditionally for convertible devices.
|
|
95
|
+
# Enum retained so legacy stored projects still deserialize; no code
|
|
96
|
+
# path emits new decisions of this type.
|
|
97
|
+
DEVICE_FIRMWARE_CONVERTIBLE = "DEVICE_FIRMWARE_CONVERTIBLE"
|
|
98
|
+
SHARED_LINE_COMPLEX = "SHARED_LINE_COMPLEX"
|
|
99
|
+
CSS_ROUTING_MISMATCH = "CSS_ROUTING_MISMATCH"
|
|
100
|
+
CALLING_PERMISSION_MISMATCH = "CALLING_PERMISSION_MISMATCH"
|
|
101
|
+
LOCATION_AMBIGUOUS = "LOCATION_AMBIGUOUS"
|
|
102
|
+
DUPLICATE_USER = "DUPLICATE_USER"
|
|
103
|
+
VOICEMAIL_INCOMPATIBLE = "VOICEMAIL_INCOMPATIBLE"
|
|
104
|
+
WORKSPACE_LICENSE_TIER = "WORKSPACE_LICENSE_TIER"
|
|
105
|
+
WORKSPACE_TYPE_UNCERTAIN = "WORKSPACE_TYPE_UNCERTAIN"
|
|
106
|
+
HOTDESK_DN_CONFLICT = "HOTDESK_DN_CONFLICT"
|
|
107
|
+
FEATURE_APPROXIMATION = "FEATURE_APPROXIMATION"
|
|
108
|
+
MISSING_DATA = "MISSING_DATA"
|
|
109
|
+
# Preflight-only decision types (from 05a-preflight-checks.md)
|
|
110
|
+
NUMBER_CONFLICT = "NUMBER_CONFLICT"
|
|
111
|
+
# Advisory system (from migration-advisory-design.md §3.1)
|
|
112
|
+
ARCHITECTURE_ADVISORY = "ARCHITECTURE_ADVISORY"
|
|
113
|
+
# Tier 2 decision types
|
|
114
|
+
FORWARDING_LOSSY = "FORWARDING_LOSSY"
|
|
115
|
+
SNR_LOSSY = "SNR_LOSSY"
|
|
116
|
+
AUDIO_ASSET_MANUAL = "AUDIO_ASSET_MANUAL"
|
|
117
|
+
BUTTON_UNMAPPABLE = "BUTTON_UNMAPPABLE"
|
|
118
|
+
DEVICE_SETTINGS_LOSSY = "DEVICE_SETTINGS_LOSSY"
|
|
119
|
+
# E911/ECBN execution (from 2026-04-10-e911-ecbn-execution.md §4.3)
|
|
120
|
+
E911_ECBN_AMBIGUOUS = "E911_ECBN_AMBIGUOUS"
|
|
121
|
+
E911_LOCATION_MISMATCH = "E911_LOCATION_MISMATCH"
|
|
122
|
+
# Workspace call settings (from 2026-04-10-workspace-call-settings.md §5)
|
|
123
|
+
WORKSPACE_SETTINGS_PROFESSIONAL_REQUIRED = "WORKSPACE_SETTINGS_PROFESSIONAL_REQUIRED"
|
|
124
|
+
# DECT Phase 2 decision types
|
|
125
|
+
DECT_NETWORK_DESIGN = "DECT_NETWORK_DESIGN"
|
|
126
|
+
DECT_HANDSET_ASSIGNMENT = "DECT_HANDSET_ASSIGNMENT"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# ---------------------------------------------------------------------------
|
|
130
|
+
# Base types
|
|
131
|
+
# ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
class Provenance(BaseModel):
|
|
134
|
+
"""Tracks where a canonical object came from.
|
|
135
|
+
(from cucm-wxc-migration.md lines 125-131)
|
|
136
|
+
"""
|
|
137
|
+
source_system: str # "cucm" or "webex"
|
|
138
|
+
source_id: str # CUCM pkid or Webex UUID
|
|
139
|
+
source_name: str
|
|
140
|
+
cluster: str | None = None
|
|
141
|
+
extracted_at: datetime
|
|
142
|
+
cucm_version: str | None = None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class MigrationObject(BaseModel):
|
|
146
|
+
"""Base for all migratable objects.
|
|
147
|
+
(from cucm-wxc-migration.md lines 133-143)
|
|
148
|
+
"""
|
|
149
|
+
canonical_id: str
|
|
150
|
+
provenance: Provenance
|
|
151
|
+
status: MigrationStatus = MigrationStatus.DISCOVERED
|
|
152
|
+
webex_id: str | None = None
|
|
153
|
+
pre_migration_state: dict[str, Any] | None = None
|
|
154
|
+
errors: list[str] = Field(default_factory=list)
|
|
155
|
+
warnings: list[str] = Field(default_factory=list)
|
|
156
|
+
depends_on: list[str] = Field(default_factory=list)
|
|
157
|
+
batch: str | None = None
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# ---------------------------------------------------------------------------
|
|
161
|
+
# Decision types — used by mappers and analyzers
|
|
162
|
+
# ---------------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
class DecisionOption(BaseModel):
|
|
165
|
+
"""One selectable resolution for a Decision.
|
|
166
|
+
(from 03b-transform-mappers.md, shared patterns — Decision Option Builder)
|
|
167
|
+
"""
|
|
168
|
+
id: str # "skip", "virtual_line", "convert", etc.
|
|
169
|
+
label: str # Human-readable: "Virtual Line"
|
|
170
|
+
impact: str # "1 virtual line + 4 line assignments"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class Decision(BaseModel):
|
|
174
|
+
"""A migration decision requiring user (or auto-rule) resolution.
|
|
175
|
+
(from 03b-transform-mappers.md, shared patterns — _create_decision helper)
|
|
176
|
+
(from 01-data-representation.md, decisions table lines 63-77)
|
|
177
|
+
"""
|
|
178
|
+
decision_id: str # Auto-incrementing via store.next_decision_id()
|
|
179
|
+
type: DecisionType # Enum of 20 decision types
|
|
180
|
+
severity: str # "LOW", "MEDIUM", "HIGH", "CRITICAL"
|
|
181
|
+
summary: str # Human-readable one-liner
|
|
182
|
+
context: dict[str, Any] # JSON blob with full details
|
|
183
|
+
options: list[DecisionOption] # Available resolution options
|
|
184
|
+
chosen_option: str | None = None # Set when resolved
|
|
185
|
+
resolved_at: str | None = None
|
|
186
|
+
# Production writers set one of: "user" (interactive CLI resolve),
|
|
187
|
+
# "auto_rule" (unified auto-matcher), "batch" (batch --choice resolve),
|
|
188
|
+
# "stale" (superseded by a fingerprint re-run). Historical stored rows
|
|
189
|
+
# from projects predating the Bug F unification may still carry the
|
|
190
|
+
# legacy "auto_apply" marker — new filter/report code should treat it
|
|
191
|
+
# as equivalent to "auto_rule" for backwards compatibility.
|
|
192
|
+
resolved_by: str | None = None
|
|
193
|
+
fingerprint: str # Hash of causal data
|
|
194
|
+
run_id: str # Analysis run identifier
|
|
195
|
+
affected_objects: list[str] = Field(default_factory=list) # canonical_ids affected
|
|
196
|
+
recommendation: str | None = None
|
|
197
|
+
recommendation_reasoning: str | None = None
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class MapperResult(BaseModel):
|
|
201
|
+
"""Return type for Mapper.map().
|
|
202
|
+
(from 03b-transform-mappers.md, mapper contract)
|
|
203
|
+
"""
|
|
204
|
+
objects_created: int = 0
|
|
205
|
+
objects_updated: int = 0
|
|
206
|
+
decisions: list[Decision] = Field(default_factory=list)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class MapperError(BaseModel):
|
|
210
|
+
"""Records a mapper-level error for TransformResult.
|
|
211
|
+
(from 03b-transform-mappers.md, shared patterns — MapperError)
|
|
212
|
+
"""
|
|
213
|
+
mapper_name: str
|
|
214
|
+
error_message: str
|
|
215
|
+
traceback: str | None = None
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class TransformResult(BaseModel):
|
|
219
|
+
"""Aggregate result from running all mappers in the transform engine.
|
|
220
|
+
(from 03b-transform-mappers.md, shared patterns — TransformResult)
|
|
221
|
+
"""
|
|
222
|
+
decisions: list[Decision] = Field(default_factory=list)
|
|
223
|
+
errors: list[MapperError] = Field(default_factory=list)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
# ---------------------------------------------------------------------------
|
|
227
|
+
# Canonical types — Location & Routing infrastructure
|
|
228
|
+
# ---------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
class LocationAddress(BaseModel):
|
|
231
|
+
"""Address fields for a Webex location.
|
|
232
|
+
(from 03b-transform-mappers.md, location_mapper field table lines 80-84)
|
|
233
|
+
"""
|
|
234
|
+
address1: str | None = None
|
|
235
|
+
city: str | None = None
|
|
236
|
+
state: str | None = None
|
|
237
|
+
postal_code: str | None = None
|
|
238
|
+
country: str | None = None
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class CanonicalLocation(MigrationObject):
|
|
242
|
+
"""CUCM Device Pool -> Webex Calling Location.
|
|
243
|
+
(from 03b-transform-mappers.md, location_mapper section lines 66-121)
|
|
244
|
+
"""
|
|
245
|
+
name: str | None = None
|
|
246
|
+
time_zone: str | None = None
|
|
247
|
+
preferred_language: str | None = None
|
|
248
|
+
announcement_language: str | None = None
|
|
249
|
+
address: LocationAddress = Field(default_factory=LocationAddress)
|
|
250
|
+
routing_prefix: str | None = None
|
|
251
|
+
outside_dial_digit: str | None = None
|
|
252
|
+
calling_enabled: bool = True
|
|
253
|
+
main_number: str | None = None
|
|
254
|
+
# CUCM metadata
|
|
255
|
+
cucm_device_pool_names: list[str] = Field(default_factory=list)
|
|
256
|
+
cucm_datetime_group_name: str | None = None
|
|
257
|
+
cucm_location_name: str | None = None
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class TrunkGatewayRef(BaseModel):
|
|
261
|
+
"""Reference to a trunk within a route group, with priority.
|
|
262
|
+
(from 03b-transform-mappers.md, routing_mapper route group field table line 387)
|
|
263
|
+
"""
|
|
264
|
+
trunk_canonical_id: str
|
|
265
|
+
priority: int = 1
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
class CanonicalTrunk(MigrationObject):
|
|
269
|
+
"""CUCM Gateway/SIP Trunk -> Webex Calling Trunk.
|
|
270
|
+
(from 03b-transform-mappers.md, routing_mapper trunk field table lines 366-380)
|
|
271
|
+
"""
|
|
272
|
+
name: str | None = None
|
|
273
|
+
location_id: str | None = None
|
|
274
|
+
trunk_type: str | None = None # REGISTERING or CERTIFICATE_BASED
|
|
275
|
+
address: str | None = None # FQDN or SRV record
|
|
276
|
+
domain: str | None = None
|
|
277
|
+
port: int | None = None
|
|
278
|
+
max_concurrent_calls: int | None = None
|
|
279
|
+
password: str | None = None # generated placeholder
|
|
280
|
+
dual_identity_support_enabled: bool | None = None
|
|
281
|
+
device_type: str | None = None # immutable after creation
|
|
282
|
+
p_charge_info_support_policy: str | None = None
|
|
283
|
+
# SIP/Security profile detail (from Tier 2 expansion)
|
|
284
|
+
sip_profile_early_offer: bool | None = None
|
|
285
|
+
sip_profile_srtp_fallback: bool | None = None
|
|
286
|
+
security_mode: str | None = None # NON_SECURE, TLS, IPSEC
|
|
287
|
+
security_digest_auth: bool | None = None
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class CanonicalRouteGroup(MigrationObject):
|
|
291
|
+
"""CUCM Route Group -> Webex Calling Route Group.
|
|
292
|
+
(from 03b-transform-mappers.md, routing_mapper route group field table lines 382-387)
|
|
293
|
+
"""
|
|
294
|
+
name: str | None = None
|
|
295
|
+
local_gateways: list[TrunkGatewayRef] = Field(default_factory=list)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class CanonicalRouteList(MigrationObject):
|
|
299
|
+
"""CUCM Route List -> Webex Calling Route List.
|
|
300
|
+
|
|
301
|
+
Webex route lists bind to exactly ONE route group (unlike CUCM which allows
|
|
302
|
+
multiple). Dial plans point to route groups, not route lists, because Webex
|
|
303
|
+
RouteType enum = ROUTE_GROUP | TRUNK only.
|
|
304
|
+
"""
|
|
305
|
+
name: str = ""
|
|
306
|
+
location_id: str | None = None
|
|
307
|
+
route_group_id: str | None = None
|
|
308
|
+
numbers: list[str] = Field(default_factory=list)
|
|
309
|
+
cucm_route_list_name: str = ""
|
|
310
|
+
cucm_route_groups: list[str] = Field(default_factory=list)
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class CanonicalDialPlan(MigrationObject):
|
|
315
|
+
"""CUCM Route Patterns / CSS routing scope -> Webex Calling Dial Plan.
|
|
316
|
+
(from 03b-transform-mappers.md, routing_mapper dial plan lines 389-395
|
|
317
|
+
and css_mapper dial plan lines 469-475)
|
|
318
|
+
"""
|
|
319
|
+
name: str | None = None
|
|
320
|
+
dial_patterns: list[str] = Field(default_factory=list)
|
|
321
|
+
route_id: str | None = None
|
|
322
|
+
route_type: str | None = None # TRUNK or ROUTE_GROUP
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class CanonicalTranslationPattern(MigrationObject):
|
|
326
|
+
"""CUCM Translation Pattern -> Webex Calling Translation Pattern.
|
|
327
|
+
(from 03b-transform-mappers.md, routing_mapper translation pattern lines 411-417)
|
|
328
|
+
"""
|
|
329
|
+
name: str | None = None
|
|
330
|
+
matching_pattern: str | None = None
|
|
331
|
+
replacement_pattern: str | None = None
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
# ---------------------------------------------------------------------------
|
|
335
|
+
# Canonical types — Users, Lines, Devices, Workspaces
|
|
336
|
+
# ---------------------------------------------------------------------------
|
|
337
|
+
|
|
338
|
+
class CanonicalUser(MigrationObject):
|
|
339
|
+
"""CUCM End User -> Webex Calling Person.
|
|
340
|
+
(from 03b-transform-mappers.md, user_mapper field table lines 130-148)
|
|
341
|
+
"""
|
|
342
|
+
emails: list[str] = Field(default_factory=list)
|
|
343
|
+
first_name: str | None = None
|
|
344
|
+
last_name: str | None = None
|
|
345
|
+
display_name: str | None = None
|
|
346
|
+
location_id: str | None = None # canonical_id of CanonicalLocation
|
|
347
|
+
extension: str | None = None
|
|
348
|
+
phone_numbers: list[dict[str, str]] = Field(default_factory=list)
|
|
349
|
+
department: str | None = None
|
|
350
|
+
title: str | None = None
|
|
351
|
+
create_method: str | None = None # "scim" or "people_api"
|
|
352
|
+
calling_data: bool = True # must pass callingData=true in API calls
|
|
353
|
+
# CUCM metadata
|
|
354
|
+
cucm_manager_user_id: str | None = None
|
|
355
|
+
cucm_userid: str | None = None
|
|
356
|
+
cucm_mailid: str | None = None
|
|
357
|
+
# Enrichment fields (set by mappers, consumed by planner)
|
|
358
|
+
voicemail_profile_id: str | None = None
|
|
359
|
+
call_settings: dict[str, Any] | None = None
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class CanonicalLine(MigrationObject):
|
|
363
|
+
"""CUCM DN/Line -> Webex Phone Number + Extension.
|
|
364
|
+
(from 03b-transform-mappers.md, line_mapper field table lines 190-199)
|
|
365
|
+
"""
|
|
366
|
+
extension: str | None = None
|
|
367
|
+
e164: str | None = None
|
|
368
|
+
classification: LineClassification | None = None
|
|
369
|
+
shared: bool = False
|
|
370
|
+
# CUCM metadata
|
|
371
|
+
cucm_pattern: str | None = None
|
|
372
|
+
route_partition_name: str | None = None
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class CanonicalDevice(MigrationObject):
|
|
376
|
+
"""CUCM Phone -> Webex Calling Device.
|
|
377
|
+
(from 03b-transform-mappers.md, device_mapper field table lines 252-266)
|
|
378
|
+
"""
|
|
379
|
+
mac: str | None = None
|
|
380
|
+
model: str | None = None
|
|
381
|
+
compatibility_tier: DeviceCompatibilityTier | None = None
|
|
382
|
+
display_name: str | None = None
|
|
383
|
+
owner_canonical_id: str | None = None # canonical_id of CanonicalUser
|
|
384
|
+
location_canonical_id: str | None = None
|
|
385
|
+
line_appearances: list[dict[str, Any]] = Field(default_factory=list)
|
|
386
|
+
# CUCM metadata
|
|
387
|
+
cucm_protocol: str | None = None # SIP or SCCP
|
|
388
|
+
cucm_device_name: str | None = None
|
|
389
|
+
device_id_surface: str = "telephony" # "telephony" (MPP) or "cloud" (9800/8875/PhoneOS)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
class CanonicalWorkspace(MigrationObject):
|
|
393
|
+
"""CUCM Common-area Phone -> Webex Workspace + Device.
|
|
394
|
+
(from 03b-transform-mappers.md, workspace_mapper field table lines 314-328)
|
|
395
|
+
"""
|
|
396
|
+
display_name: str | None = None
|
|
397
|
+
location_id: str | None = None
|
|
398
|
+
supported_devices: str | None = None # "phones" or "collaborationDevices"
|
|
399
|
+
extension: str | None = None
|
|
400
|
+
phone_number: str | None = None
|
|
401
|
+
calling_type: str = "webexCalling"
|
|
402
|
+
workspace_type: str | None = None # meetingRoom, desk, other
|
|
403
|
+
hotdesking_status: str | None = None # on or off
|
|
404
|
+
is_common_area: bool = True
|
|
405
|
+
license_tier: str | None = None # Workspace or Professional Workspace
|
|
406
|
+
call_settings: dict[str, Any] | None = None
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
# ---------------------------------------------------------------------------
|
|
410
|
+
# Canonical types — Call Features
|
|
411
|
+
# ---------------------------------------------------------------------------
|
|
412
|
+
|
|
413
|
+
class CanonicalHuntGroup(MigrationObject):
|
|
414
|
+
"""CUCM Hunt Pilot + Hunt List + Line Group -> Webex Hunt Group.
|
|
415
|
+
(from 03b-transform-mappers.md, feature_mapper HG field table lines 601-614)
|
|
416
|
+
"""
|
|
417
|
+
name: str | None = None
|
|
418
|
+
extension: str | None = None
|
|
419
|
+
phone_number: str | None = None
|
|
420
|
+
policy: str | None = None # REGULAR, CIRCULAR, UNIFORM, SIMULTANEOUS
|
|
421
|
+
agents: list[str] = Field(default_factory=list)
|
|
422
|
+
no_answer_rings: int | None = None
|
|
423
|
+
enabled: bool = True
|
|
424
|
+
location_id: str | None = None
|
|
425
|
+
# Forwarding configuration (from 2026-04-10-feature-forwarding-night-service.md)
|
|
426
|
+
forward_always_enabled: bool = False
|
|
427
|
+
forward_always_destination: str | None = None
|
|
428
|
+
forward_busy_enabled: bool = False
|
|
429
|
+
forward_busy_destination: str | None = None
|
|
430
|
+
forward_no_answer_enabled: bool = False
|
|
431
|
+
forward_no_answer_destination: str | None = None
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
class CanonicalCallQueue(MigrationObject):
|
|
435
|
+
"""Queue-style CUCM Hunt Pilot -> Webex Call Queue.
|
|
436
|
+
(from 03b-transform-mappers.md, feature_mapper CQ field table lines 616-627)
|
|
437
|
+
"""
|
|
438
|
+
name: str | None = None
|
|
439
|
+
extension: str | None = None
|
|
440
|
+
phone_number: str | None = None
|
|
441
|
+
policy: str | None = None # REGULAR, CIRCULAR, UNIFORM
|
|
442
|
+
routing_type: str = "PRIORITY_BASED"
|
|
443
|
+
agents: list[str] = Field(default_factory=list)
|
|
444
|
+
queue_size: int = 25
|
|
445
|
+
enabled: bool = True
|
|
446
|
+
location_id: str | None = None
|
|
447
|
+
# Forwarding configuration (from 2026-04-10-feature-forwarding-night-service.md)
|
|
448
|
+
forward_always_enabled: bool = False
|
|
449
|
+
forward_always_destination: str | None = None
|
|
450
|
+
# Overflow destinations from CUCM queueCalls
|
|
451
|
+
queue_full_destination: str | None = None
|
|
452
|
+
max_wait_time_destination: str | None = None
|
|
453
|
+
max_wait_time: int | None = None
|
|
454
|
+
no_agent_destination: str | None = None
|
|
455
|
+
# Holiday service
|
|
456
|
+
holiday_service_enabled: bool = False
|
|
457
|
+
holiday_schedule_name: str | None = None
|
|
458
|
+
holiday_schedule_level: str = "LOCATION"
|
|
459
|
+
holiday_action: str = "BUSY"
|
|
460
|
+
holiday_transfer_number: str | None = None
|
|
461
|
+
# Night service
|
|
462
|
+
night_service_enabled: bool = False
|
|
463
|
+
night_business_hours_name: str | None = None
|
|
464
|
+
night_business_hours_level: str = "LOCATION"
|
|
465
|
+
night_action: str = "TRANSFER"
|
|
466
|
+
night_transfer_number: str | None = None
|
|
467
|
+
# Forced forward (currently unused — left for future spec)
|
|
468
|
+
forced_forward_enabled: bool = False
|
|
469
|
+
forced_forward_number: str | None = None
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
class CanonicalAutoAttendant(MigrationObject):
|
|
473
|
+
"""CUCM CTI Route Point + Script -> Webex Auto Attendant.
|
|
474
|
+
(from 03b-transform-mappers.md, feature_mapper AA field table lines 629-638)
|
|
475
|
+
"""
|
|
476
|
+
name: str | None = None
|
|
477
|
+
extension: str | None = None
|
|
478
|
+
phone_number: str | None = None
|
|
479
|
+
business_schedule: str | None = None
|
|
480
|
+
business_hours_menu: dict[str, Any] | None = None
|
|
481
|
+
after_hours_menu: dict[str, Any] | None = None
|
|
482
|
+
location_id: str | None = None
|
|
483
|
+
# Forwarding configuration (from 2026-04-10-feature-forwarding-night-service.md)
|
|
484
|
+
forward_always_enabled: bool = False
|
|
485
|
+
forward_always_destination: str | None = None
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
class CanonicalCallPark(MigrationObject):
|
|
489
|
+
"""CUCM Call Park Number -> Webex Call Park Extension.
|
|
490
|
+
(from 03b-transform-mappers.md, feature_mapper simple features line 644)
|
|
491
|
+
"""
|
|
492
|
+
name: str | None = None
|
|
493
|
+
extension: str | None = None
|
|
494
|
+
location_id: str | None = None
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
class CanonicalPickupGroup(MigrationObject):
|
|
498
|
+
"""CUCM Pickup Group -> Webex Call Pickup.
|
|
499
|
+
(from 03b-transform-mappers.md, feature_mapper simple features line 645)
|
|
500
|
+
"""
|
|
501
|
+
name: str | None = None
|
|
502
|
+
agents: list[str] = Field(default_factory=list)
|
|
503
|
+
location_id: str | None = None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
class CanonicalPagingGroup(MigrationObject):
|
|
507
|
+
"""CUCM Paging -> Webex Paging Group.
|
|
508
|
+
(from 03b-transform-mappers.md, feature_mapper simple features line 646)
|
|
509
|
+
"""
|
|
510
|
+
name: str | None = None
|
|
511
|
+
extension: str | None = None
|
|
512
|
+
targets: list[str] = Field(default_factory=list)
|
|
513
|
+
originators: list[str] = Field(default_factory=list)
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
class CanonicalOperatingMode(MigrationObject):
|
|
517
|
+
"""CUCM Time Period + Time Schedule -> Webex Operating Mode.
|
|
518
|
+
(from 03b-transform-mappers.md, feature_mapper simple features line 647)
|
|
519
|
+
"""
|
|
520
|
+
name: str | None = None
|
|
521
|
+
level: str = "ORGANIZATION"
|
|
522
|
+
schedule_type: str | None = None # SAME_HOURS_DAILY, DIFFERENT_HOURS_DAILY, HOLIDAY
|
|
523
|
+
location_id: str | None = None
|
|
524
|
+
same_hours_daily: dict[str, Any] | None = None
|
|
525
|
+
different_hours_daily: dict[str, Any] | None = None
|
|
526
|
+
holidays: list[dict[str, Any]] = Field(default_factory=list)
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
class CanonicalLocationSchedule(MigrationObject):
|
|
530
|
+
"""CUCM Time Schedule -> Webex Location Schedule.
|
|
531
|
+
Created for schedules referenced by AAs, CQs, or HGs.
|
|
532
|
+
(from fix-schedule-mapping-and-skill-gaps.md Fix 1)
|
|
533
|
+
"""
|
|
534
|
+
name: str | None = None
|
|
535
|
+
schedule_type: str | None = None # businessHours or holidays
|
|
536
|
+
location_id: str | None = None
|
|
537
|
+
events: list[dict[str, Any]] = Field(default_factory=list)
|
|
538
|
+
# Reference back to the operating mode (same CUCM source)
|
|
539
|
+
operating_mode_canonical_id: str | None = None
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
# ---------------------------------------------------------------------------
|
|
543
|
+
# Canonical types — Voicemail, Shared Lines, Virtual Lines, Permissions
|
|
544
|
+
# ---------------------------------------------------------------------------
|
|
545
|
+
|
|
546
|
+
class CanonicalVoicemailProfile(MigrationObject):
|
|
547
|
+
"""CUCM Unity Connection VM Profile -> Webex per-person voicemail settings.
|
|
548
|
+
(from 03b-transform-mappers.md, voicemail_mapper field table lines 699-724)
|
|
549
|
+
"""
|
|
550
|
+
enabled: bool = True
|
|
551
|
+
send_all_calls: dict[str, Any] | None = None
|
|
552
|
+
send_busy_calls: dict[str, Any] | None = None
|
|
553
|
+
send_unanswered_calls: dict[str, Any] | None = None
|
|
554
|
+
notifications: dict[str, Any] | None = None
|
|
555
|
+
email_copy_of_message: dict[str, Any] | None = None
|
|
556
|
+
message_storage: dict[str, Any] | None = None
|
|
557
|
+
fax_message: dict[str, Any] | None = None
|
|
558
|
+
transfer_to_number: dict[str, Any] | None = None
|
|
559
|
+
# CUCM metadata
|
|
560
|
+
cucm_voicemail_profile_name: str | None = None
|
|
561
|
+
user_canonical_id: str | None = None
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
class CanonicalVoicemailGroup(MigrationObject):
|
|
565
|
+
"""Unity Connection shared/group mailbox -> Webex Voicemail Group.
|
|
566
|
+
|
|
567
|
+
Produced by VoicemailGroupMapper. Location-scoped. Consumed by
|
|
568
|
+
handle_voicemail_group_create which POSTs to
|
|
569
|
+
/telephony/config/locations/{locationId}/voicemailGroups.
|
|
570
|
+
(from docs/superpowers/specs/2026-04-10-voicemail-groups.md)
|
|
571
|
+
"""
|
|
572
|
+
name: str | None = None
|
|
573
|
+
extension: str | None = None
|
|
574
|
+
phone_number: str | None = None
|
|
575
|
+
location_id: str | None = None # canonical_id of CanonicalLocation
|
|
576
|
+
language_code: str = "en_us"
|
|
577
|
+
enabled: bool = True
|
|
578
|
+
passcode: str | None = None # Generated by mapper (CUCM PINs not extractable)
|
|
579
|
+
greeting_type: str = "DEFAULT" # DEFAULT or CUSTOM
|
|
580
|
+
caller_id_name: str | None = None
|
|
581
|
+
# Feature settings (match Webex API shapes)
|
|
582
|
+
message_storage: dict[str, Any] = Field(
|
|
583
|
+
default_factory=lambda: {"storageType": "INTERNAL"}
|
|
584
|
+
)
|
|
585
|
+
notifications: dict[str, Any] = Field(
|
|
586
|
+
default_factory=lambda: {"enabled": False}
|
|
587
|
+
)
|
|
588
|
+
fax_message: dict[str, Any] = Field(
|
|
589
|
+
default_factory=lambda: {"enabled": False}
|
|
590
|
+
)
|
|
591
|
+
transfer_to_number: dict[str, Any] = Field(
|
|
592
|
+
default_factory=lambda: {"enabled": False}
|
|
593
|
+
)
|
|
594
|
+
email_copy_of_message: dict[str, Any] = Field(
|
|
595
|
+
default_factory=lambda: {"enabled": False}
|
|
596
|
+
)
|
|
597
|
+
# CUCM metadata
|
|
598
|
+
cucm_object_id: str | None = None # Unity Connection ObjectId
|
|
599
|
+
cucm_display_name: str | None = None
|
|
600
|
+
# Cross-reference: hunt groups/call queues that overflow to this mailbox
|
|
601
|
+
referring_features: list[str] = Field(default_factory=list)
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
class CanonicalSharedLine(MigrationObject):
|
|
605
|
+
"""Shared line appearance — DN shared across multiple devices/users.
|
|
606
|
+
(from cucm-wxc-migration.md line 185, cucm-wxc-migration.md CUCM mapping table line 204)
|
|
607
|
+
"""
|
|
608
|
+
dn_canonical_id: str | None = None # canonical_id of the shared DN
|
|
609
|
+
owner_canonical_ids: list[str] = Field(default_factory=list)
|
|
610
|
+
device_canonical_ids: list[str] = Field(default_factory=list)
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
class CanonicalVirtualLine(MigrationObject):
|
|
614
|
+
"""Virtual line — Webex Virtual Line for shared line migration.
|
|
615
|
+
(from cucm-wxc-migration.md line 186)
|
|
616
|
+
"""
|
|
617
|
+
extension: str | None = None
|
|
618
|
+
phone_number: str | None = None
|
|
619
|
+
location_id: str | None = None
|
|
620
|
+
display_name: str | None = None
|
|
621
|
+
dn_canonical_id: str | None = None
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
class CanonicalExecutiveAssistant(MigrationObject):
|
|
625
|
+
"""CUCM Executive/Assistant pairing -> Webex Executive/Assistant config.
|
|
626
|
+
(from executive-assistant-migration spec §4c)
|
|
627
|
+
"""
|
|
628
|
+
executive_canonical_id: str | None = None
|
|
629
|
+
assistant_canonical_ids: list[str] = Field(default_factory=list)
|
|
630
|
+
alerting_mode: str = "SIMULTANEOUS" # SEQUENTIAL or SIMULTANEOUS
|
|
631
|
+
filter_enabled: bool = False
|
|
632
|
+
filter_type: str = "ALL_CALLS" # ALL_CALLS, ALL_INTERNAL_CALLS, ALL_EXTERNAL_CALLS
|
|
633
|
+
screening_enabled: bool = False
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
class CallingPermissionEntry(BaseModel):
|
|
637
|
+
"""Single call type permission entry.
|
|
638
|
+
(from 03b-transform-mappers.md, css_mapper field table lines 477-486)
|
|
639
|
+
"""
|
|
640
|
+
call_type: str # e.g. INTERNAL_CALL, NATIONAL, INTERNATIONAL
|
|
641
|
+
action: str # ALLOW or BLOCK
|
|
642
|
+
transfer_enabled: bool = True
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
class CanonicalCallingPermission(MigrationObject):
|
|
646
|
+
"""CSS blocking partitions -> Webex per-user Outgoing Calling Permissions.
|
|
647
|
+
(from 03b-transform-mappers.md, css_mapper field table lines 477-486)
|
|
648
|
+
"""
|
|
649
|
+
calling_permissions: list[CallingPermissionEntry] = Field(default_factory=list)
|
|
650
|
+
assigned_users: list[str] = Field(default_factory=list)
|
|
651
|
+
use_custom_enabled: bool = True
|
|
652
|
+
use_custom_permissions: bool = True
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
# ---------------------------------------------------------------------------
|
|
656
|
+
# Canonical types — Tier 2: Call Forwarding, Monitoring
|
|
657
|
+
# ---------------------------------------------------------------------------
|
|
658
|
+
|
|
659
|
+
class CanonicalCallForwarding(MigrationObject):
|
|
660
|
+
"""CUCM per-line forwarding → Webex per-person call forwarding."""
|
|
661
|
+
user_canonical_id: str | None = None
|
|
662
|
+
always_enabled: bool = False
|
|
663
|
+
always_destination: str | None = None
|
|
664
|
+
always_to_voicemail: bool = False
|
|
665
|
+
busy_enabled: bool = False
|
|
666
|
+
busy_destination: str | None = None
|
|
667
|
+
busy_to_voicemail: bool = False
|
|
668
|
+
no_answer_enabled: bool = False
|
|
669
|
+
no_answer_destination: str | None = None
|
|
670
|
+
no_answer_to_voicemail: bool = False
|
|
671
|
+
no_answer_ring_count: int | None = None
|
|
672
|
+
busy_internal_enabled: bool = False
|
|
673
|
+
busy_internal_destination: str | None = None
|
|
674
|
+
no_answer_internal_enabled: bool = False
|
|
675
|
+
no_answer_internal_destination: str | None = None
|
|
676
|
+
no_coverage_enabled: bool = False
|
|
677
|
+
no_coverage_destination: str | None = None
|
|
678
|
+
on_failure_enabled: bool = False
|
|
679
|
+
on_failure_destination: str | None = None
|
|
680
|
+
not_registered_enabled: bool = False
|
|
681
|
+
not_registered_destination: str | None = None
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
class CanonicalMonitoringList(MigrationObject):
|
|
685
|
+
"""CUCM BLF → Webex per-person monitoring list."""
|
|
686
|
+
user_canonical_id: str | None = None
|
|
687
|
+
call_park_notification_enabled: bool = False
|
|
688
|
+
monitored_members: list[dict[str, Any]] = Field(default_factory=list)
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
class CanonicalLineKeyTemplate(MigrationObject):
|
|
692
|
+
"""CUCM Phone Button Template → Webex Line Key Template."""
|
|
693
|
+
name: str | None = None
|
|
694
|
+
cucm_template_name: str | None = None
|
|
695
|
+
device_model: str | None = None
|
|
696
|
+
line_keys: list[dict[str, Any]] = Field(default_factory=list)
|
|
697
|
+
kem_module_type: str | None = None
|
|
698
|
+
kem_keys: list[dict[str, Any]] = Field(default_factory=list)
|
|
699
|
+
unmapped_buttons: list[dict[str, Any]] = Field(default_factory=list)
|
|
700
|
+
phones_using: int = 0
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
class CanonicalDeviceLayout(MigrationObject):
|
|
704
|
+
"""Per-device resolved line key + KEM layout."""
|
|
705
|
+
device_canonical_id: str | None = None
|
|
706
|
+
template_canonical_id: str | None = None
|
|
707
|
+
owner_canonical_id: str | None = None
|
|
708
|
+
line_members: list[dict[str, Any]] = Field(default_factory=list)
|
|
709
|
+
resolved_line_keys: list[dict[str, Any]] = Field(default_factory=list)
|
|
710
|
+
resolved_kem_keys: list[dict[str, Any]] = Field(default_factory=list)
|
|
711
|
+
speed_dials: list[dict[str, Any]] = Field(default_factory=list)
|
|
712
|
+
unmapped_buttons: list[dict[str, Any]] = Field(default_factory=list)
|
|
713
|
+
device_id_surface: str = "telephony" # Copied from associated device at map time
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
class CanonicalMusicOnHold(MigrationObject):
|
|
717
|
+
"""CUCM MOH Audio Source → Webex per-location MOH."""
|
|
718
|
+
location_canonical_id: str | None = None
|
|
719
|
+
source_name: str | None = None
|
|
720
|
+
source_file_name: str | None = None
|
|
721
|
+
is_default: bool = False
|
|
722
|
+
cucm_source_id: str | None = None
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
class CanonicalAnnouncement(MigrationObject):
|
|
726
|
+
"""CUCM Announcement / Unity greeting → Webex announcement repo."""
|
|
727
|
+
name: str | None = None
|
|
728
|
+
location_canonical_id: str | None = None
|
|
729
|
+
file_name: str | None = None
|
|
730
|
+
media_type: str | None = None
|
|
731
|
+
source_system: str | None = None
|
|
732
|
+
usage: str | None = None
|
|
733
|
+
associated_feature_canonical_id: str | None = None
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
class CanonicalDeviceProfile(MigrationObject):
|
|
737
|
+
"""CUCM Device Profile → informs Webex hot desking decisions."""
|
|
738
|
+
profile_name: str | None = None
|
|
739
|
+
user_canonical_id: str | None = None
|
|
740
|
+
model: str | None = None
|
|
741
|
+
protocol: str | None = None
|
|
742
|
+
lines: list[dict[str, Any]] = Field(default_factory=list)
|
|
743
|
+
device_pool_name: str | None = None
|
|
744
|
+
speed_dial_count: int = 0
|
|
745
|
+
blf_count: int = 0
|
|
746
|
+
# Execution-ready hoteling fields (from hoteling-migration spec §6a)
|
|
747
|
+
hoteling_guest_enabled: bool = False
|
|
748
|
+
host_device_canonical_ids: list[str] = Field(default_factory=list)
|
|
749
|
+
auto_logout_minutes: int = 0
|
|
750
|
+
location_canonical_id: str | None = None
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
class CanonicalReceptionistConfig(MigrationObject):
|
|
754
|
+
"""Receptionist configuration detected from CUCM phone layout signals."""
|
|
755
|
+
user_canonical_id: str = ""
|
|
756
|
+
location_canonical_id: str = ""
|
|
757
|
+
blf_count: int = 0
|
|
758
|
+
has_kem: bool = False
|
|
759
|
+
kem_key_count: int = 0
|
|
760
|
+
template_name: str = ""
|
|
761
|
+
detection_score: int = 0
|
|
762
|
+
detection_reasons: list[str] = Field(default_factory=list)
|
|
763
|
+
monitored_members: list[str] = Field(default_factory=list)
|
|
764
|
+
is_main_number_holder: bool = False
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
class CanonicalE911Config(MigrationObject):
|
|
768
|
+
"""CUCM ELIN/GeoLocation → Webex E911 advisory."""
|
|
769
|
+
location_canonical_id: str | None = None
|
|
770
|
+
elin_group_name: str | None = None
|
|
771
|
+
elin_numbers: list[str] = Field(default_factory=list)
|
|
772
|
+
geo_location_name: str | None = None
|
|
773
|
+
geo_country: str | None = None
|
|
774
|
+
has_emergency_route_pattern: bool = False
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
class CanonicalEcbnConfig(MigrationObject):
|
|
778
|
+
"""Per-entity ECBN configuration for Webex.
|
|
779
|
+
|
|
780
|
+
One object per user, workspace, or virtual line. Produced by EcbnMapper
|
|
781
|
+
from existing canonical data (no new AXL queries).
|
|
782
|
+
(from 2026-04-10-e911-ecbn-execution.md §4.2)
|
|
783
|
+
"""
|
|
784
|
+
entity_type: str = "" # "user" | "workspace" | "virtual_line"
|
|
785
|
+
entity_canonical_id: str = "" # canonical_id of the user/workspace/VL
|
|
786
|
+
location_canonical_id: str | None = None
|
|
787
|
+
ecbn_selection: str = "" # "DIRECT_LINE" | "LOCATION_ECBN" | "LOCATION_MEMBER_NUMBER"
|
|
788
|
+
did_numbers: list[str] = Field(default_factory=list) # all DIDs on this entity
|
|
789
|
+
primary_did: str | None = None # best candidate DID for ECBN
|
|
790
|
+
needs_location_ecbn: bool = False # True if extension-only; location ECBN must exist
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
class CanonicalSingleNumberReach(MigrationObject):
|
|
794
|
+
"""CUCM Remote Destination → Webex Single Number Reach."""
|
|
795
|
+
user_canonical_id: str | None = None
|
|
796
|
+
enabled: bool = True
|
|
797
|
+
alert_click_to_dial: bool = False
|
|
798
|
+
numbers: list[dict[str, Any]] = Field(default_factory=list)
|
|
799
|
+
# Each entry: {phone_number, enabled, name, answer_confirmation,
|
|
800
|
+
# cucm_answer_too_soon, cucm_answer_too_late}
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
class CanonicalSoftkeyConfig(MigrationObject):
|
|
804
|
+
"""CUCM Softkey Template → Webex PSK config (9800/8875) or report flag (classic MPP)."""
|
|
805
|
+
cucm_template_name: str | None = None
|
|
806
|
+
is_psk_target: bool = False
|
|
807
|
+
psk_mappings: list[dict[str, Any]] = Field(default_factory=list)
|
|
808
|
+
state_key_lists: dict[str, list[str]] = Field(default_factory=dict)
|
|
809
|
+
unmapped_softkeys: list[dict[str, Any]] = Field(default_factory=list)
|
|
810
|
+
phones_using: int = 0
|
|
811
|
+
device_canonical_id: str | None = None # Per-device PSK config: links to device
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
class CanonicalDeviceSettingsTemplate(MigrationObject):
|
|
815
|
+
"""CUCM device settings -> Webex device settings template.
|
|
816
|
+
|
|
817
|
+
One template per (model_family, location) group. Settings are the
|
|
818
|
+
majority-vote values across all phones in the group. Per-device overrides
|
|
819
|
+
list phones that differ from the majority.
|
|
820
|
+
"""
|
|
821
|
+
model_family: str | None = None # "9800", "8875", "78xx", "68xx"
|
|
822
|
+
location_canonical_id: str | None = None
|
|
823
|
+
settings: dict[str, Any] = Field(default_factory=dict)
|
|
824
|
+
per_device_overrides: list[dict[str, Any]] = Field(default_factory=list)
|
|
825
|
+
unmappable_settings: list[str] = Field(default_factory=list)
|
|
826
|
+
phones_using: int = 0
|
|
827
|
+
custom_backgrounds: list[str] = Field(default_factory=list)
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
# ---------------------------------------------------------------------------
|
|
831
|
+
# Canonical types — DECT Networks
|
|
832
|
+
# ---------------------------------------------------------------------------
|
|
833
|
+
|
|
834
|
+
class CanonicalDECTNetwork(MigrationObject):
|
|
835
|
+
"""CUCM DECT infrastructure → Webex DECT Network + Base Stations + Handsets.
|
|
836
|
+
|
|
837
|
+
Produced by DECTMapper (Phase 2). One object per CUCM DECT network (identified
|
|
838
|
+
by access_code + base station cluster). Consumed by DECT execution handlers
|
|
839
|
+
which POST to /telephony/config/locations/{locationId}/dectNetworks.
|
|
840
|
+
"""
|
|
841
|
+
location_canonical_id: str | None = None # canonical_id of CanonicalLocation
|
|
842
|
+
network_name: str | None = None # Internal name for the network
|
|
843
|
+
display_name: str | None = None # User-visible display name
|
|
844
|
+
model: str | None = None # DECT network model (e.g., "DBS-110", "DBS-210")
|
|
845
|
+
access_code: str | None = None # DECT system access code
|
|
846
|
+
base_stations: list[dict[str, Any]] = Field(default_factory=list)
|
|
847
|
+
# Each base station entry: {mac, display_name, location_canonical_id, cucm_device_name}
|
|
848
|
+
handset_assignments: list[dict[str, Any]] = Field(default_factory=list)
|
|
849
|
+
# Each handset entry: {index, line1_canonical_id, line2_canonical_id,
|
|
850
|
+
# display_name, user_canonical_id}
|
|
851
|
+
pre_migration_state: dict[str, Any] | None = None
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
# ---------------------------------------------------------------------------
|
|
855
|
+
# Inventory — aggregates all canonical types
|
|
856
|
+
# ---------------------------------------------------------------------------
|
|
857
|
+
|
|
858
|
+
class MigrationInventory(BaseModel):
|
|
859
|
+
"""Single source of truth for the migration.
|
|
860
|
+
(from cucm-wxc-migration.md lines 165-189)
|
|
861
|
+
|
|
862
|
+
Note: The design spec also defines ``unmapped`` and ``pending_decisions``
|
|
863
|
+
fields. These are intentionally omitted here because the SQLite store
|
|
864
|
+
(MigrationStore) is the authoritative source for decisions and unmapped
|
|
865
|
+
objects are tracked via MigrationStatus. The ``wxcli cucm export`` command
|
|
866
|
+
populates these on-demand from the store when generating JSON views.
|
|
867
|
+
"""
|
|
868
|
+
project_id: str
|
|
869
|
+
cucm_cluster: str
|
|
870
|
+
locations: list[CanonicalLocation] = Field(default_factory=list)
|
|
871
|
+
users: list[CanonicalUser] = Field(default_factory=list)
|
|
872
|
+
devices: list[CanonicalDevice] = Field(default_factory=list)
|
|
873
|
+
lines: list[CanonicalLine] = Field(default_factory=list)
|
|
874
|
+
hunt_groups: list[CanonicalHuntGroup] = Field(default_factory=list)
|
|
875
|
+
call_queues: list[CanonicalCallQueue] = Field(default_factory=list)
|
|
876
|
+
auto_attendants: list[CanonicalAutoAttendant] = Field(default_factory=list)
|
|
877
|
+
trunks: list[CanonicalTrunk] = Field(default_factory=list)
|
|
878
|
+
dial_plans: list[CanonicalDialPlan] = Field(default_factory=list)
|
|
879
|
+
route_groups: list[CanonicalRouteGroup] = Field(default_factory=list)
|
|
880
|
+
translation_patterns: list[CanonicalTranslationPattern] = Field(default_factory=list)
|
|
881
|
+
operating_modes: list[CanonicalOperatingMode] = Field(default_factory=list)
|
|
882
|
+
call_parks: list[CanonicalCallPark] = Field(default_factory=list)
|
|
883
|
+
pickup_groups: list[CanonicalPickupGroup] = Field(default_factory=list)
|
|
884
|
+
paging_groups: list[CanonicalPagingGroup] = Field(default_factory=list)
|
|
885
|
+
voicemail_profiles: list[CanonicalVoicemailProfile] = Field(default_factory=list)
|
|
886
|
+
shared_lines: list[CanonicalSharedLine] = Field(default_factory=list)
|
|
887
|
+
virtual_lines: list[CanonicalVirtualLine] = Field(default_factory=list)
|
|
888
|
+
workspaces: list[CanonicalWorkspace] = Field(default_factory=list)
|
|
889
|
+
calling_permissions: list[CanonicalCallingPermission] = Field(default_factory=list)
|
|
890
|
+
schedules: list[CanonicalLocationSchedule] = Field(default_factory=list)
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
# ---------------------------------------------------------------------------
|
|
894
|
+
# Type registry — maps object_type strings to classes for deserialization
|
|
895
|
+
# ---------------------------------------------------------------------------
|
|
896
|
+
|
|
897
|
+
CANONICAL_TYPE_REGISTRY: dict[str, type[MigrationObject]] = {
|
|
898
|
+
"location": CanonicalLocation,
|
|
899
|
+
"user": CanonicalUser,
|
|
900
|
+
"device": CanonicalDevice,
|
|
901
|
+
"line": CanonicalLine,
|
|
902
|
+
"hunt_group": CanonicalHuntGroup,
|
|
903
|
+
"call_queue": CanonicalCallQueue,
|
|
904
|
+
"auto_attendant": CanonicalAutoAttendant,
|
|
905
|
+
"trunk": CanonicalTrunk,
|
|
906
|
+
"dial_plan": CanonicalDialPlan,
|
|
907
|
+
"route_group": CanonicalRouteGroup,
|
|
908
|
+
"route_list": CanonicalRouteList,
|
|
909
|
+
"translation_pattern": CanonicalTranslationPattern,
|
|
910
|
+
"operating_mode": CanonicalOperatingMode,
|
|
911
|
+
"call_park": CanonicalCallPark,
|
|
912
|
+
"pickup_group": CanonicalPickupGroup,
|
|
913
|
+
"paging_group": CanonicalPagingGroup,
|
|
914
|
+
"voicemail_profile": CanonicalVoicemailProfile,
|
|
915
|
+
"voicemail_group": CanonicalVoicemailGroup,
|
|
916
|
+
"shared_line": CanonicalSharedLine,
|
|
917
|
+
"virtual_line": CanonicalVirtualLine,
|
|
918
|
+
"workspace": CanonicalWorkspace,
|
|
919
|
+
"calling_permission": CanonicalCallingPermission,
|
|
920
|
+
"schedule": CanonicalLocationSchedule,
|
|
921
|
+
"call_forwarding": CanonicalCallForwarding,
|
|
922
|
+
"monitoring_list": CanonicalMonitoringList,
|
|
923
|
+
"line_key_template": CanonicalLineKeyTemplate,
|
|
924
|
+
"device_layout": CanonicalDeviceLayout,
|
|
925
|
+
"softkey_config": CanonicalSoftkeyConfig,
|
|
926
|
+
"single_number_reach": CanonicalSingleNumberReach,
|
|
927
|
+
"e911_config": CanonicalE911Config,
|
|
928
|
+
"ecbn_config": CanonicalEcbnConfig,
|
|
929
|
+
"device_profile": CanonicalDeviceProfile,
|
|
930
|
+
"receptionist_config": CanonicalReceptionistConfig,
|
|
931
|
+
"music_on_hold": CanonicalMusicOnHold,
|
|
932
|
+
"announcement": CanonicalAnnouncement,
|
|
933
|
+
"device_settings_template": CanonicalDeviceSettingsTemplate,
|
|
934
|
+
"executive_assistant": CanonicalExecutiveAssistant,
|
|
935
|
+
"dect_network": CanonicalDECTNetwork,
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
# Reverse lookup: class -> type name string (O(1) for _object_type_for)
|
|
939
|
+
CANONICAL_CLASS_TO_TYPE: dict[type[MigrationObject], str] = {
|
|
940
|
+
cls: name for name, cls in CANONICAL_TYPE_REGISTRY.items()
|
|
941
|
+
}
|