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,1262 @@
|
|
|
1
|
+
<!-- Not directly verified via CLI — documents wxcadm library (not generated CLI commands) -->
|
|
2
|
+
<!-- wxcadm v4.6.1 review 2026-03-27: All v4.5.0–v4.6.1 changes verified present. RouteLists.create(), CallRouting(org) signature, Webhooks(org) signature, PSTNProviderList/LocationPSTN parent→location renaming, NumberList(org, location) signature — all accurately documented. No discrepancies found. -->
|
|
3
|
+
# wxcadm -- Routing, PSTN, CDR, Reports, Jobs, Webhooks
|
|
4
|
+
|
|
5
|
+
Reference for the secondary wxcadm modules that handle call routing infrastructure, PSTN configuration, call detail records, reporting, asynchronous jobs, and webhooks.
|
|
6
|
+
|
|
7
|
+
Source files:
|
|
8
|
+
- `wxcadm/call_routing.py` -- dial plans, trunks, route groups, route lists, translation patterns
|
|
9
|
+
- `wxcadm/pstn.py` -- PSTN provider config per location
|
|
10
|
+
- `wxcadm/cdr.py` -- call detail record processing
|
|
11
|
+
- `wxcadm/reports.py` -- report generation and retrieval
|
|
12
|
+
- `wxcadm/jobs.py` -- async job management (number moves, user moves, phone rebuilds)
|
|
13
|
+
- `wxcadm/webhooks.py` -- webhook CRUD
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
18
|
+
## When to Use wxcadm vs Raw HTTP
|
|
19
|
+
|
|
20
|
+
| Use wxcadm when | Use raw HTTP when |
|
|
21
|
+
|---|---|
|
|
22
|
+
| CDR post-processing -- the `Call -> CallLeg -> LegPart` hierarchy with automatic transfer merging is unique to wxcadm and has no raw HTTP equivalent | Call routing CRUD (trunks, route groups, route lists, dial plans, translation patterns) |
|
|
23
|
+
| You need the two-phase validate-then-move pattern for `UserMoveJobList` in a single call | PSTN provider configuration per location |
|
|
24
|
+
| Object-graph navigation for routing (e.g., `org.call_routing.trunks.get(name=...)`) is more convenient than tracking IDs | Report creation, job management, webhook CRUD |
|
|
25
|
+
|
|
26
|
+
> **Note:** The playbook uses raw HTTP via `api.session.rest_*()` for standard CRUD operations. All routing, PSTN, report, job, and webhook endpoints are standard Webex REST APIs that work fine with raw HTTP. wxcadm's unique value here is the CDR parsing module (`CallDetailRecords`) which builds a structured call hierarchy from raw CSV records.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Table of Contents
|
|
31
|
+
|
|
32
|
+
1. [Call Routing](#1-call-routing)
|
|
33
|
+
- [CallRouting (entry point)](#callrouting-entry-point)
|
|
34
|
+
- [Trunks / Trunk](#trunks--trunk)
|
|
35
|
+
- [RouteGroups / RouteGroup](#routegroups--routegroup)
|
|
36
|
+
- [RouteLists / RouteList](#routelists--routelist)
|
|
37
|
+
- [DialPlans / DialPlan](#dialplans--dialplan)
|
|
38
|
+
- [TranslationPatternList / TranslationPattern](#translationpatternlist--translationpattern)
|
|
39
|
+
2. [PSTN Configuration](#2-pstn-configuration)
|
|
40
|
+
3. [Call Detail Records (CDR)](#3-call-detail-records-cdr)
|
|
41
|
+
4. [Reports](#4-reports)
|
|
42
|
+
5. [Jobs](#5-jobs)
|
|
43
|
+
- [Number Management Jobs](#number-management-jobs)
|
|
44
|
+
- [User Move Jobs](#user-move-jobs)
|
|
45
|
+
- [Rebuild Phones Jobs](#rebuild-phones-jobs)
|
|
46
|
+
6. [Webhooks](#6-webhooks)
|
|
47
|
+
7. [wxcadm vs wxc_sdk Comparison](#7-wxcadm-vs-wxc_sdk-comparison)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 1. Call Routing
|
|
52
|
+
|
|
53
|
+
All call routing objects live under `org.call_routing`, which returns a `CallRouting` instance. The API base path for premise PSTN routing is `/v1/telephony/config/premisePstn/`. Translation patterns use `/v1/telephony/config/callRouting/translationPatterns`.
|
|
54
|
+
|
|
55
|
+
### CallRouting (entry point)
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
class CallRouting:
|
|
59
|
+
def __init__(self, org: wxcadm.Org)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Properties** (each returns a freshly-initialized collection -- no caching):
|
|
63
|
+
|
|
64
|
+
| Property | Returns | Description |
|
|
65
|
+
|----------|---------|-------------|
|
|
66
|
+
| `trunks` | `Trunks` | All trunks in the org |
|
|
67
|
+
| `route_groups` | `RouteGroups` | All route groups in the org |
|
|
68
|
+
| `route_lists` | `RouteLists` | All route lists in the org |
|
|
69
|
+
| `dial_plans` | `DialPlans` | All dial plans in the org |
|
|
70
|
+
|
|
71
|
+
**Methods:**
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
def test(
|
|
75
|
+
self,
|
|
76
|
+
originator: Person | Trunk,
|
|
77
|
+
destination: str,
|
|
78
|
+
orig_number: Optional[str] = None
|
|
79
|
+
) -> dict
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Tests call routing for a given originator and destination. The `originator` must be a `Person` or `Trunk` instance -- the method determines `originatorType` (`USER` or `TRUNK`) automatically. `orig_number` is only used for `TRUNK` originators. Returns the raw API response dict because the response format varies by routing outcome.
|
|
83
|
+
|
|
84
|
+
API endpoint: `POST /v1/telephony/config/actions/testCallRouting/invoke`
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### Trunks / Trunk
|
|
89
|
+
|
|
90
|
+
#### Trunks (collection)
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
class Trunks(UserList):
|
|
94
|
+
def __init__(self, org: wxcadm.Org)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Fetches all trunks on init from `GET /v1/telephony/config/premisePstn/trunks` (items key: `trunks`). Iterable list of `Trunk` instances.
|
|
98
|
+
|
|
99
|
+
**Methods:**
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
def get(
|
|
103
|
+
self,
|
|
104
|
+
name: Optional[str] = None,
|
|
105
|
+
id: Optional[str] = None
|
|
106
|
+
) -> Optional[Trunk]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Find a trunk by name or ID. Raises `ValueError` if both are `None`.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
def add_trunk(
|
|
113
|
+
self,
|
|
114
|
+
name: str,
|
|
115
|
+
location: Location | str,
|
|
116
|
+
password: str,
|
|
117
|
+
dual_identity_support: bool,
|
|
118
|
+
type: str, # 'REGISTERING' or 'CERTIFICATE_BASED'
|
|
119
|
+
device_type: Optional[str] = 'Cisco Unified Border Element',
|
|
120
|
+
address: Optional[str] = None, # required for certificate-based
|
|
121
|
+
domain: Optional[str] = None, # required for certificate-based
|
|
122
|
+
port: Optional[int] = None, # required for certificate-based
|
|
123
|
+
max_concurrent_calls: Optional[int] = None # required for certificate-based
|
|
124
|
+
) -> bool
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Creates a new trunk. For `CERTIFICATE_BASED` type, the optional parameters (`address`, `domain`, `port`, `max_concurrent_calls`) are required. Returns `True` on success, `False` otherwise.
|
|
128
|
+
|
|
129
|
+
#### Trunk (dataclass)
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
@dataclass_json
|
|
133
|
+
@dataclass
|
|
134
|
+
class Trunk:
|
|
135
|
+
org: wxcadm.Org
|
|
136
|
+
id: str
|
|
137
|
+
name: str
|
|
138
|
+
location: dict | Location # resolved to Location in __post_init__
|
|
139
|
+
in_use: bool # JSON field: "inUse"
|
|
140
|
+
trunk_type: str # JSON field: "trunkType" -- 'REGISTERING' or 'CERTIFICATE_BASED'
|
|
141
|
+
dedicated_instance_only: bool # JSON field: "isRestrictedToDedicatedInstance"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Lazy-loaded detail fields** (populated on first attribute access via `__getattr__`, triggering `GET /v1/telephony/config/premisePstn/trunks/{id}`):
|
|
145
|
+
|
|
146
|
+
| Attribute | Type | Description |
|
|
147
|
+
|-----------|------|-------------|
|
|
148
|
+
| `otg_dtg` | `str` | OTG/DTG identifier |
|
|
149
|
+
| `lineport` | `str` | Line/Port identifier |
|
|
150
|
+
| `used_by_locations` | `list[dict]` | Locations using this trunk for PSTN |
|
|
151
|
+
| `pilot_user_id` | `str` | Pilot user ID |
|
|
152
|
+
| `outbound_proxy` | `OutboundProxy | None` | Outbound proxy config |
|
|
153
|
+
| `sip_auth_user` | `str` | SIP auth username |
|
|
154
|
+
| `status` | `str` | Trunk status |
|
|
155
|
+
| `response_status` | `list` | Status messages |
|
|
156
|
+
| `dual_identity_support` | `bool` | Dual identity flag |
|
|
157
|
+
| `device_type` | `str` | Device type |
|
|
158
|
+
| `max_calls` | `int` | Max concurrent calls |
|
|
159
|
+
|
|
160
|
+
**Methods:**
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
def set_dual_identity_support(self, enabled: bool) -> bool
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Sets the dual identity support flag. Returns `True` on success. Raises `wxcadm.ApiError` on API failure.
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
def set_max_calls(self, calls: int) -> bool
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Sets max concurrent calls. Only supported for `CERTIFICATE_BASED` trunks. Raises `ValueError` for registering trunks.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### RouteGroups / RouteGroup
|
|
177
|
+
|
|
178
|
+
#### RouteGroups (collection)
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
class RouteGroups(UserList):
|
|
182
|
+
def __init__(self, org: wxcadm.Org)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Fetches from `GET /v1/telephony/config/premisePstn/routeGroups` (items key: `routeGroups`).
|
|
186
|
+
|
|
187
|
+
**Methods:**
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
def get(
|
|
191
|
+
self,
|
|
192
|
+
id: Optional[str] = None,
|
|
193
|
+
name: Optional[str] = None
|
|
194
|
+
) -> Optional[RouteGroup]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Find a route group by ID or name.
|
|
198
|
+
|
|
199
|
+
#### RouteGroup (dataclass)
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
@dataclass
|
|
203
|
+
class RouteGroup:
|
|
204
|
+
org: wxcadm.Org
|
|
205
|
+
id: str
|
|
206
|
+
name: str
|
|
207
|
+
inUse: bool # whether the route group is used by any location, route list, or dial plan
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Properties:**
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
@property
|
|
214
|
+
def trunks(self) -> List[dict]
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Returns the trunks within the route group with their priorities. Each dict contains trunk details and a `priority` key. Fetches from `GET /v1/telephony/config/premisePstn/routeGroups/{id}` (items key: `localGateways`).
|
|
218
|
+
|
|
219
|
+
**Methods:**
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
def add_trunk(
|
|
223
|
+
self,
|
|
224
|
+
trunk: Trunk,
|
|
225
|
+
priority: Union[str, int] # int, or 'next' / 'with_last'
|
|
226
|
+
) -> bool
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Adds a trunk to the route group. The `priority` parameter accepts:
|
|
230
|
+
- An `int` for a specific priority value
|
|
231
|
+
- `'next'` to set priority one higher than the current highest
|
|
232
|
+
- `'with_last'` to match the current highest priority (equal weight)
|
|
233
|
+
|
|
234
|
+
Returns `True` on success.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
### RouteLists / RouteList
|
|
239
|
+
|
|
240
|
+
#### RouteLists (collection)
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
class RouteLists(UserList):
|
|
244
|
+
def __init__(self, org: wxcadm.Org)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Fetches from `GET /v1/telephony/config/premisePstn/routeLists` (items key: `routeLists`).
|
|
248
|
+
|
|
249
|
+
**Methods:**
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
def create(
|
|
253
|
+
self,
|
|
254
|
+
location: Location,
|
|
255
|
+
route_group: RouteGroup,
|
|
256
|
+
name: str
|
|
257
|
+
) -> RouteList
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Creates a new route list and returns the `RouteList` instance.
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
def get(
|
|
264
|
+
self,
|
|
265
|
+
name: Optional[str] = None,
|
|
266
|
+
id: Optional[str] = None
|
|
267
|
+
) -> Optional[RouteList]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Find a route list by name or ID. Raises `ValueError` if both are `None`.
|
|
271
|
+
|
|
272
|
+
#### RouteList (dataclass)
|
|
273
|
+
|
|
274
|
+
```python
|
|
275
|
+
@dataclass
|
|
276
|
+
class RouteList:
|
|
277
|
+
org: wxcadm.Org
|
|
278
|
+
id: str
|
|
279
|
+
name: str
|
|
280
|
+
locationId: str # resolved to Location instance in __post_init__
|
|
281
|
+
locationName: str # deleted after __post_init__
|
|
282
|
+
routeGroupId: str # resolved to RouteGroup instance in __post_init__
|
|
283
|
+
routeGroupName: str # deleted after __post_init__
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
After `__post_init__`, the raw ID/name fields are replaced with:
|
|
287
|
+
- `self.location` -- resolved `Location` instance
|
|
288
|
+
- `self.route_group` -- resolved `RouteGroup` instance
|
|
289
|
+
|
|
290
|
+
**Bug:** `__post_init__` calls `self.org.call_routing.route_groups.get_route_group(id=...)` but the `RouteGroups` class only defines `get()`, not `get_route_group()`. This will raise `AttributeError` at runtime when a `RouteList` is instantiated. Workaround: iterate `route_groups` manually or call `.get(id=...)` instead.
|
|
291
|
+
|
|
292
|
+
**Properties:**
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
@property
|
|
296
|
+
def numbers(self)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Returns the numbers assigned to this route list. Fetches from `GET /v1/telephony/config/premisePstn/routeLists/{id}/numbers`.
|
|
300
|
+
|
|
301
|
+
**Bug:** The `numbers` property calls `response.json()` on the return value of `org.api.get()`, but `org.api.get()` already returns a parsed dict (not a raw `Response` object). This will raise `AttributeError: 'dict' object has no attribute 'json'` at runtime. Workaround: use raw HTTP `GET /v1/telephony/config/premisePstn/routeLists/{id}/numbers` instead.
|
|
302
|
+
|
|
303
|
+
**Not implemented:** Delete route list (noted as TODO in source).
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### DialPlans / DialPlan
|
|
308
|
+
|
|
309
|
+
#### DialPlans (collection)
|
|
310
|
+
|
|
311
|
+
```python
|
|
312
|
+
class DialPlans(UserList):
|
|
313
|
+
def __init__(self, org: wxcadm.Org)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Fetches from `GET /v1/telephony/config/premisePstn/dialPlans` (items key: `dialPlans`).
|
|
317
|
+
|
|
318
|
+
No `get()` method is defined on the collection. To find a specific dial plan, iterate manually:
|
|
319
|
+
|
|
320
|
+
```python
|
|
321
|
+
dp = next((d for d in org.call_routing.dial_plans if d.name == "My Plan"), None)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
#### DialPlan (dataclass)
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
@dataclass
|
|
328
|
+
class DialPlan:
|
|
329
|
+
org: wxcadm.Org
|
|
330
|
+
id: str
|
|
331
|
+
name: str
|
|
332
|
+
routeId: str # ID of the route (trunk, route group, or route list)
|
|
333
|
+
routeName: str # name of the route
|
|
334
|
+
routeType: str # type of the route
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
**Properties:**
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
@property
|
|
341
|
+
def patterns(self) -> list
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Returns the dial patterns within the dial plan. Fetches from `GET /v1/telephony/config/premisePstn/dialPlans/{id}/dialPatterns` (items key: `dialPatterns`).
|
|
345
|
+
|
|
346
|
+
**Methods:**
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
def add_pattern(self, pattern: str) -> bool
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Adds a dial pattern. Sends `PUT` with action `ADD`. Returns `True` on success.
|
|
353
|
+
|
|
354
|
+
```python
|
|
355
|
+
def delete_pattern(self, pattern: str) -> bool
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Deletes an existing dial pattern. Sends `PUT` with action `DELETE`. Returns `True` on success.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
### TranslationPatternList / TranslationPattern
|
|
363
|
+
|
|
364
|
+
Translation patterns can exist at org level or location level.
|
|
365
|
+
|
|
366
|
+
#### TranslationPatternList (collection)
|
|
367
|
+
|
|
368
|
+
```python
|
|
369
|
+
class TranslationPatternList(UserList):
|
|
370
|
+
def __init__(
|
|
371
|
+
self,
|
|
372
|
+
org: wxcadm.Org,
|
|
373
|
+
location: Optional[Location] = None
|
|
374
|
+
)
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
If `location` is provided, fetches patterns scoped to that location via `limitToLocationId` param. Otherwise fetches all org-level patterns.
|
|
378
|
+
|
|
379
|
+
API endpoint: `GET /v1/telephony/config/callRouting/translationPatterns`
|
|
380
|
+
|
|
381
|
+
**Methods:**
|
|
382
|
+
|
|
383
|
+
```python
|
|
384
|
+
def refresh(self) -> list
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Re-fetches the list from the API. Returns the updated data list.
|
|
388
|
+
|
|
389
|
+
```python
|
|
390
|
+
def get(
|
|
391
|
+
self,
|
|
392
|
+
id: Optional[str] = None,
|
|
393
|
+
name: Optional[str] = None,
|
|
394
|
+
match_pattern: Optional[str] = None,
|
|
395
|
+
replacement_pattern: Optional[str] = None
|
|
396
|
+
) -> Optional[TranslationPattern]
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
Finds a translation pattern matching ALL provided criteria (AND logic). Any parameter left as `None` is treated as a wildcard.
|
|
400
|
+
|
|
401
|
+
```python
|
|
402
|
+
def create(
|
|
403
|
+
self,
|
|
404
|
+
name: str,
|
|
405
|
+
match_pattern: str,
|
|
406
|
+
replacement_pattern: str,
|
|
407
|
+
location: Optional[Location] = None
|
|
408
|
+
) -> TranslationPattern
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Creates a new translation pattern. Scope logic:
|
|
412
|
+
- If `location` argument is provided, creates at that location's scope
|
|
413
|
+
- If no `location` argument but the list was initialized with a location, uses the list's location
|
|
414
|
+
- Otherwise creates at org scope
|
|
415
|
+
|
|
416
|
+
Returns the newly created `TranslationPattern` instance (fetched back from API after creation).
|
|
417
|
+
|
|
418
|
+
#### TranslationPattern
|
|
419
|
+
|
|
420
|
+
```python
|
|
421
|
+
class TranslationPattern:
|
|
422
|
+
def __init__(
|
|
423
|
+
self,
|
|
424
|
+
org: wxcadm.Org,
|
|
425
|
+
location: Optional[Location] = None,
|
|
426
|
+
config: Optional[dict] = None
|
|
427
|
+
)
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
**Attributes:**
|
|
431
|
+
|
|
432
|
+
| Attribute | Type | Description |
|
|
433
|
+
|-----------|------|-------------|
|
|
434
|
+
| `id` | `str` | Unique identifier |
|
|
435
|
+
| `name` | `str` | Pattern name |
|
|
436
|
+
| `match_pattern` | `str` | The pattern to match (from `matchingPattern`) |
|
|
437
|
+
| `replacement_pattern` | `str` | The replacement (from `replacementPattern`) |
|
|
438
|
+
| `location` | `Location | None` | Associated location, or `None` for org-level |
|
|
439
|
+
| `level` | `str | None` | `'Location'` or `None` |
|
|
440
|
+
|
|
441
|
+
**Methods:**
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
def update(
|
|
445
|
+
self,
|
|
446
|
+
name: Optional[str] = None,
|
|
447
|
+
match_pattern: Optional[str] = None,
|
|
448
|
+
replacement_pattern: Optional[str] = None
|
|
449
|
+
) -> bool
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
Updates the translation pattern. Only provided fields are changed; `None` fields keep current values. Uses location-scoped or org-scoped URL based on `self.location`. Returns `True` on success.
|
|
453
|
+
|
|
454
|
+
```python
|
|
455
|
+
def delete(self) -> bool
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Deletes the translation pattern. Returns `True` on success.
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## 2. PSTN Configuration
|
|
463
|
+
|
|
464
|
+
PSTN config is location-scoped, accessed via `LocationPSTN`.
|
|
465
|
+
|
|
466
|
+
### LocationPSTN
|
|
467
|
+
|
|
468
|
+
```python
|
|
469
|
+
class LocationPSTN:
|
|
470
|
+
def __init__(self, location: wxcadm.Location)
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
On init, fetches the current PSTN connection for the location from `GET /v1/telephony/pstn/locations/{id}/connection`. If no PSTN is configured, `self.provider` is set to `None` (does not raise).
|
|
474
|
+
|
|
475
|
+
**Attributes:**
|
|
476
|
+
|
|
477
|
+
| Attribute | Type | Description |
|
|
478
|
+
|-----------|------|-------------|
|
|
479
|
+
| `location` | `Location` | The associated location |
|
|
480
|
+
| `available_providers` | `PSTNProviderList` | Available PSTN providers for this location |
|
|
481
|
+
| `provider` | `PSTNProvider | None` | Currently configured provider |
|
|
482
|
+
| `type` | `str` | PSTN connection type (e.g. `pstnConnectionType` value) |
|
|
483
|
+
|
|
484
|
+
**Methods:**
|
|
485
|
+
|
|
486
|
+
```python
|
|
487
|
+
def set_provider(
|
|
488
|
+
self,
|
|
489
|
+
provider: PSTNProvider | str | RouteGroup | Trunk
|
|
490
|
+
) -> bool
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Sets the PSTN provider for the location. Accepts:
|
|
494
|
+
- `PSTNProvider` instance -- sets by provider ID
|
|
495
|
+
- `str` -- looked up as a provider ID in `available_providers`
|
|
496
|
+
- `Trunk` -- sets `premiseRouteType: 'TRUNK'` with the trunk ID
|
|
497
|
+
- `RouteGroup` -- sets `premiseRouteType: 'ROUTE_GROUP'` with the route group ID
|
|
498
|
+
|
|
499
|
+
Returns `True` on success.
|
|
500
|
+
|
|
501
|
+
API endpoint: `PUT /v1/telephony/pstn/locations/{id}/connection`
|
|
502
|
+
|
|
503
|
+
### PSTNProvider (dataclass)
|
|
504
|
+
|
|
505
|
+
```python
|
|
506
|
+
@dataclass_json
|
|
507
|
+
@dataclass
|
|
508
|
+
class PSTNProvider:
|
|
509
|
+
id: str
|
|
510
|
+
name: str # JSON field: "displayName"
|
|
511
|
+
services: list # JSON field: "pstnServices"
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### PSTNProviderList (collection)
|
|
515
|
+
|
|
516
|
+
```python
|
|
517
|
+
class PSTNProviderList(UserList):
|
|
518
|
+
def __init__(self, location: wxcadm.Location)
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
Fetches available connection options from `GET /v1/telephony/pstn/locations/{id}/connectionOptions`.
|
|
522
|
+
|
|
523
|
+
**Methods:**
|
|
524
|
+
|
|
525
|
+
```python
|
|
526
|
+
def get(
|
|
527
|
+
self,
|
|
528
|
+
id: Optional[str] = None,
|
|
529
|
+
name: Optional[str] = None
|
|
530
|
+
) -> Optional[PSTNProvider]
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
Find a provider by ID or name.
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## 3. Call Detail Records (CDR)
|
|
538
|
+
|
|
539
|
+
The CDR module processes raw CDR records into a structured call hierarchy. **It does not fetch CDRs from the API directly** -- records must be obtained externally (typically via the Reports module's `cdr_report()` method) and passed in as a list of dicts with raw CSV field names.
|
|
540
|
+
|
|
541
|
+
### Data Model Hierarchy
|
|
542
|
+
|
|
543
|
+
```
|
|
544
|
+
CallDetailRecords
|
|
545
|
+
-> calls: list[Call]
|
|
546
|
+
-> legs: list[CallLeg]
|
|
547
|
+
-> parts: list[LegPart]
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### CallDetailRecords (entry point)
|
|
551
|
+
|
|
552
|
+
```python
|
|
553
|
+
class CallDetailRecords:
|
|
554
|
+
def __init__(
|
|
555
|
+
self,
|
|
556
|
+
records: list, # list of dicts with raw CDR field names
|
|
557
|
+
webex: Optional[wxcadm.Webex] = None # enables user/endpoint lookup
|
|
558
|
+
)
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
On init, processes all records into `Call` objects and merges transferred calls based on matching part IDs within a 24-hour window.
|
|
562
|
+
|
|
563
|
+
**Attributes:**
|
|
564
|
+
|
|
565
|
+
| Attribute | Type | Description |
|
|
566
|
+
|-----------|------|-------------|
|
|
567
|
+
| `records` | `list` | The raw records passed in |
|
|
568
|
+
| `webex` | `Webex | None` | Webex connection for resolving user IDs |
|
|
569
|
+
| `calls` | `list[Call]` | Unordered list of processed calls |
|
|
570
|
+
|
|
571
|
+
**Properties:**
|
|
572
|
+
|
|
573
|
+
```python
|
|
574
|
+
@property
|
|
575
|
+
def calls_sorted(self) -> list[Call]
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
Returns calls sorted by start time (ascending).
|
|
579
|
+
|
|
580
|
+
**Methods:**
|
|
581
|
+
|
|
582
|
+
```python
|
|
583
|
+
def get_call_by_correlation_id(self, correlation_id: str) -> Optional[Call]
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
```python
|
|
587
|
+
def get_call_by_part_call_id(self, part_call_id: str) -> Optional[Call]
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
```python
|
|
591
|
+
def get_abandoned_calls(self) -> list[Call]
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
Returns calls where the caller hung up in a call queue before an agent answered.
|
|
595
|
+
|
|
596
|
+
```python
|
|
597
|
+
def get_pstn_calls(self) -> list[Call]
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
Returns calls with at least one PSTN (off-net) leg.
|
|
601
|
+
|
|
602
|
+
```python
|
|
603
|
+
def get_voicemail_deposit_calls(self) -> list[Call]
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
Returns calls where the caller was sent to voicemail.
|
|
607
|
+
|
|
608
|
+
### Call
|
|
609
|
+
|
|
610
|
+
```python
|
|
611
|
+
class Call:
|
|
612
|
+
def __init__(self, correlation_id: str)
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
**Attributes:**
|
|
616
|
+
- `id` (`str`) -- the correlation ID
|
|
617
|
+
- `legs` (`list[CallLeg]`) -- the call legs
|
|
618
|
+
- `correlation_ids` (`list[str]`) -- all correlation IDs (includes merged transfers)
|
|
619
|
+
|
|
620
|
+
**Properties:**
|
|
621
|
+
|
|
622
|
+
| Property | Type | Description |
|
|
623
|
+
|----------|------|-------------|
|
|
624
|
+
| `start_time` | `datetime` | Earliest leg start time |
|
|
625
|
+
| `end_time` | `datetime` | Latest leg end time |
|
|
626
|
+
| `duration` | `str` | Formatted duration (HH:MM:SS) |
|
|
627
|
+
| `calling_number` | `str` | Calling number from the first sorted leg |
|
|
628
|
+
| `leg_count` | `int` | Number of legs |
|
|
629
|
+
| `legs_sorted` | `list[CallLeg]` | Legs sorted by start time |
|
|
630
|
+
| `part_ids` | `set` | All part IDs in the call |
|
|
631
|
+
| `transfer_ids` | `list` | All transfer-related call IDs |
|
|
632
|
+
| `answered_legs` | `int` | Count of answered legs |
|
|
633
|
+
| `has_queue_leg` | `bool` | Whether any leg involves a call queue |
|
|
634
|
+
| `has_pstn_leg` | `bool` | Whether any leg is PSTN |
|
|
635
|
+
| `has_vm_deposit_leg` | `bool` | Whether any leg is a voicemail deposit |
|
|
636
|
+
| `is_queue_abandon` | `bool` | Caller hung up in queue without agent answer |
|
|
637
|
+
|
|
638
|
+
**Methods:**
|
|
639
|
+
|
|
640
|
+
```python
|
|
641
|
+
def add_record(self, record: dict)
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
Adds a CDR record to the call, either to an existing leg (if part IDs match) or by creating a new leg.
|
|
645
|
+
|
|
646
|
+
### CallLeg
|
|
647
|
+
|
|
648
|
+
```python
|
|
649
|
+
class CallLeg:
|
|
650
|
+
def __init__(self)
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
Contains `parts: list[LegPart]`.
|
|
654
|
+
|
|
655
|
+
**Properties:**
|
|
656
|
+
|
|
657
|
+
| Property | Type | Description |
|
|
658
|
+
|----------|------|-------------|
|
|
659
|
+
| `start_time` | `datetime` | First part's start time |
|
|
660
|
+
| `end_time` | `datetime` | End time (accounts for transfers) |
|
|
661
|
+
| `pstn_leg` | `bool` | Whether this leg is PSTN |
|
|
662
|
+
| `duration` | `int` | Duration in seconds |
|
|
663
|
+
| `ring_duration` | `int` | Ring time in seconds |
|
|
664
|
+
| `transfer_ids` | `list` | Transfer-related call IDs |
|
|
665
|
+
| `orig_part` | `LegPart | None` | Originating part |
|
|
666
|
+
| `term_part` | `LegPart | None` | Terminating part |
|
|
667
|
+
| `is_queue_leg` | `bool` | Terminating user type is `CALLCENTERPREMIUM` |
|
|
668
|
+
| `is_aa_leg` | `bool` | Terminating user type is `AUTOMATEDATTENDANTVIDEO` |
|
|
669
|
+
| `is_agent_leg` | `bool` | User type `USER` with redirect reason `CALLQUEUE` |
|
|
670
|
+
| `is_vm_deposit` | `bool` | Called line is `Voice Portal Voice Messaging Group` |
|
|
671
|
+
| `label` | `str` | Display label for the leg |
|
|
672
|
+
| `calling_number` | `str` | Calling party number |
|
|
673
|
+
| `leg_description` | `str` | "From X to Y" description |
|
|
674
|
+
| `new_leg_description` | `str` | Enhanced description with reasons |
|
|
675
|
+
| `in_reason` | `str | None` | Why the leg was received (e.g. `SIP Inbound`, redirect reason) |
|
|
676
|
+
| `out_reason` | `str | None` | Why the leg originated (e.g. `Queue Callback`) |
|
|
677
|
+
| `answered` | `bool` | Whether any part was answered |
|
|
678
|
+
| `answered_label` | `str` | `'Answered'` or `'Unanswered'` |
|
|
679
|
+
| `parts_id` | `list` | All local and remote IDs from parts |
|
|
680
|
+
| `recorded` | `bool` | Whether any part has a successful recording |
|
|
681
|
+
|
|
682
|
+
**Methods:**
|
|
683
|
+
|
|
684
|
+
```python
|
|
685
|
+
def add_part(self, record: dict) -> LegPart
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
### LegPart
|
|
689
|
+
|
|
690
|
+
```python
|
|
691
|
+
class LegPart:
|
|
692
|
+
def __init__(self, record: dict)
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Wraps a single CDR record. Key attributes parsed from the raw dict:
|
|
696
|
+
|
|
697
|
+
| Attribute | Source Field | Type |
|
|
698
|
+
|-----------|-------------|------|
|
|
699
|
+
| `start_time` | `Start time` | `datetime` |
|
|
700
|
+
| `end_time` | `Release time` | `datetime` |
|
|
701
|
+
| `answer_time` | `Answer time` | `datetime | None` |
|
|
702
|
+
| `answered` | `Answered` | `bool` |
|
|
703
|
+
| `local_id` | `Local call ID` | `str | None` |
|
|
704
|
+
| `remote_id` | `Remote call ID` | `str | None` |
|
|
705
|
+
| `direction` | `Direction` | `str` |
|
|
706
|
+
| `calling_line_id` | `Calling line ID` | `str` |
|
|
707
|
+
| `called_line_id` | `Called line ID` | `str` |
|
|
708
|
+
| `dialed_digits` | `Dialed digits` | `str` |
|
|
709
|
+
| `user_number` | `User number` | `str` |
|
|
710
|
+
| `called_number` | `Called number` | `str` |
|
|
711
|
+
| `calling_number` | `Calling number` | `str` |
|
|
712
|
+
| `redirecting_number` | `Redirecting number` | `str` |
|
|
713
|
+
| `location_name` | `Location` | `str` |
|
|
714
|
+
| `user_type` | `User type` | `str` |
|
|
715
|
+
| `user` | `User` | `str` |
|
|
716
|
+
| `call_type` | `Call type` | `str` |
|
|
717
|
+
| `duration` | `Duration` | `str` |
|
|
718
|
+
| `time_offset` | `Site timezone` | `str` |
|
|
719
|
+
| `releasing_party` | `Releasing party` | `str` |
|
|
720
|
+
| `original_reason` | `Original reason` | `str` |
|
|
721
|
+
| `redirect_reason` | `Redirect reason` | `str` |
|
|
722
|
+
| `related_reason` | `Related reason` | `str` |
|
|
723
|
+
| `outcome` | `Call outcome` | `str` |
|
|
724
|
+
| `outcome_reason` | `Call outcome reason` | `str` |
|
|
725
|
+
| `ring_duration` | `Ring duration` | `str` |
|
|
726
|
+
| `device_owner_uuid` | `Device owner UUID` | `str` |
|
|
727
|
+
| `recording_platform` | `Call Recording Platform Name` | `str` |
|
|
728
|
+
| `recording_result` | `Call Recording Result` | `str` |
|
|
729
|
+
| `recording_trigger` | `Call Recording Trigger` | `str` |
|
|
730
|
+
| `device_mac` | `Device MAC` or `Device Mac` | `str` |
|
|
731
|
+
| `transfer_time` | `Call transfer time` | `datetime | None` |
|
|
732
|
+
| `transfer_related_call_id` | `Transfer related call ID` | `str` |
|
|
733
|
+
| `pstn_inbound` | derived | `bool` -- `True` if call type is `SIP_INBOUND` |
|
|
734
|
+
| `internal_call` | derived | `bool` -- `True` if call type is `SIP_ENTERPRISE` |
|
|
735
|
+
| `pstn_outbound` | derived | `bool` -- `True` if call type is `SIP NATIONAL` or `SIP_INTERNATIONAL` |
|
|
736
|
+
|
|
737
|
+
---
|
|
738
|
+
|
|
739
|
+
## 4. Reports
|
|
740
|
+
|
|
741
|
+
Report management lives under `org.reports`, which returns a `ReportList` instance.
|
|
742
|
+
|
|
743
|
+
### ReportList (collection)
|
|
744
|
+
|
|
745
|
+
```python
|
|
746
|
+
class ReportList(UserList):
|
|
747
|
+
def __init__(self, org: wxcadm.Org)
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
Fetches existing reports on init from `GET /v1/reports`.
|
|
751
|
+
|
|
752
|
+
**Properties:**
|
|
753
|
+
|
|
754
|
+
```python
|
|
755
|
+
@property
|
|
756
|
+
def templates(self) -> list[ReportTemplate]
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
Lazy-loaded list of available report templates from `GET /v1/report/templates`.
|
|
760
|
+
|
|
761
|
+
**Methods:**
|
|
762
|
+
|
|
763
|
+
```python
|
|
764
|
+
def get_template(self, id: int) -> Optional[ReportTemplate]
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
Find a template by ID.
|
|
768
|
+
|
|
769
|
+
```python
|
|
770
|
+
def list_reports(self) -> list[Report]
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
Returns the current list of reports. Note: only shows API-created reports, not Control Hub reports.
|
|
774
|
+
|
|
775
|
+
```python
|
|
776
|
+
def create_report(
|
|
777
|
+
self,
|
|
778
|
+
template: ReportTemplate,
|
|
779
|
+
start_date: Optional[str] = None,
|
|
780
|
+
end_date: Optional[str] = None,
|
|
781
|
+
site_list: Optional[list] = None
|
|
782
|
+
) -> Report
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
Creates a new report. Arguments depend on the template's `validations`.
|
|
786
|
+
|
|
787
|
+
```python
|
|
788
|
+
def delete_report(self, report_id: str) -> bool
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
Deletes a report. Returns `True` on success, `False` on exception.
|
|
792
|
+
|
|
793
|
+
```python
|
|
794
|
+
def report_status(self, report_id: str) -> Optional[str]
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
Returns the current status string of a report (triggers a refresh).
|
|
798
|
+
|
|
799
|
+
```python
|
|
800
|
+
def get_report_lines(self, report_id: str) -> Optional[list]
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
Downloads and returns the report lines as a list.
|
|
804
|
+
|
|
805
|
+
```python
|
|
806
|
+
def cdr_report(
|
|
807
|
+
self,
|
|
808
|
+
start: Optional[str] = None, # YYYY-MM-DD
|
|
809
|
+
end: Optional[str] = None, # YYYY-MM-DD
|
|
810
|
+
days: Optional[int] = None
|
|
811
|
+
) -> Report | bool
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
Shortcut to create a "Calling Detailed Call History" report. Must provide either `start`/`end` or `days` (not both). When using `days`, the end date is set to yesterday. Returns the `Report` instance, or `False` if the CDR template is not found.
|
|
815
|
+
|
|
816
|
+
### Report
|
|
817
|
+
|
|
818
|
+
```python
|
|
819
|
+
class Report:
|
|
820
|
+
def __init__(
|
|
821
|
+
self,
|
|
822
|
+
org: wxcadm.Org,
|
|
823
|
+
id: Optional[str] = None,
|
|
824
|
+
config: Optional[dict] = None
|
|
825
|
+
)
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
**Attributes:**
|
|
829
|
+
|
|
830
|
+
| Attribute | Type | Description |
|
|
831
|
+
|-----------|------|-------------|
|
|
832
|
+
| `id` | `str` | Report ID |
|
|
833
|
+
| `title` | `str` | Report title |
|
|
834
|
+
| `service` | `str` | Associated Webex service |
|
|
835
|
+
| `start_date` | `str` | Report period start |
|
|
836
|
+
| `end_date` | `str` | Report period end |
|
|
837
|
+
| `site_list` | `str` | Webex Meetings site list |
|
|
838
|
+
| `created` | `str` | Creation date |
|
|
839
|
+
| `created_by` | `str` | Creator ID |
|
|
840
|
+
| `scheduled_from` | `str` | `'API'` or `'Control Hub'` |
|
|
841
|
+
| `download_url` | `str | None` | URL to download the report |
|
|
842
|
+
|
|
843
|
+
**Properties:**
|
|
844
|
+
|
|
845
|
+
```python
|
|
846
|
+
@property
|
|
847
|
+
def status(self) -> str
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
Returns the current status. Automatically calls `refresh()` first.
|
|
851
|
+
|
|
852
|
+
**Methods:**
|
|
853
|
+
|
|
854
|
+
```python
|
|
855
|
+
def refresh(self)
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
Re-fetches report details from the API.
|
|
859
|
+
|
|
860
|
+
```python
|
|
861
|
+
def get_report_lines(self) -> list
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
Downloads the report. Handles both ZIP and plain-text content types. Returns lines as a list of strings. No further parsing is done -- the caller must split/clean lines.
|
|
865
|
+
|
|
866
|
+
### ReportTemplate
|
|
867
|
+
|
|
868
|
+
```python
|
|
869
|
+
class ReportTemplate:
|
|
870
|
+
def __init__(self, config: dict)
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
| Attribute | Type | Description |
|
|
874
|
+
|-----------|------|-------------|
|
|
875
|
+
| `id` | `str` | Template ID |
|
|
876
|
+
| `title` | `str` | Template title |
|
|
877
|
+
| `service` | `str` | Webex service |
|
|
878
|
+
| `max_days` | `int` | Maximum days the report can span |
|
|
879
|
+
| `identifier` | `str` | Additional identifiers |
|
|
880
|
+
| `validations` | `list` | Validation rules for creating a report |
|
|
881
|
+
|
|
882
|
+
---
|
|
883
|
+
|
|
884
|
+
## 5. Jobs
|
|
885
|
+
|
|
886
|
+
Three async job types are supported, all following the same pattern: a job list class (fetches/creates jobs) and a job class (tracks status).
|
|
887
|
+
|
|
888
|
+
### Number Management Jobs
|
|
889
|
+
|
|
890
|
+
For moving phone numbers between locations.
|
|
891
|
+
|
|
892
|
+
#### NumberManagementJobList
|
|
893
|
+
|
|
894
|
+
```python
|
|
895
|
+
class NumberManagementJobList(UserList):
|
|
896
|
+
def __init__(self, org: wxcadm.Org)
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
API endpoint: `v1/telephony/config/jobs/numbers/manageNumbers`
|
|
900
|
+
|
|
901
|
+
**Methods:**
|
|
902
|
+
|
|
903
|
+
```python
|
|
904
|
+
def refresh(self) -> bool
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
```python
|
|
908
|
+
def get(self, id: str) -> Optional[NumberManagementJob]
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
```python
|
|
912
|
+
def create(
|
|
913
|
+
self,
|
|
914
|
+
job_type: str, # only "move" supported
|
|
915
|
+
target_location: Location | str,
|
|
916
|
+
numbers: list[str] # list of phone numbers to move
|
|
917
|
+
) -> NumberManagementJob
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
Creates a number move job. Validates numbers against `org.numbers` first. Raises `KeyError` if a number is not found in the org.
|
|
921
|
+
|
|
922
|
+
**Limitation:** The API currently supports only a single number per job, despite the list parameter.
|
|
923
|
+
|
|
924
|
+
#### NumberManagementJob
|
|
925
|
+
|
|
926
|
+
```python
|
|
927
|
+
class NumberManagementJob:
|
|
928
|
+
def __init__(self, org: wxcadm.Org, id: str, details: Optional[dict] = None)
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
**Properties:**
|
|
932
|
+
|
|
933
|
+
```python
|
|
934
|
+
@property
|
|
935
|
+
def completed(self) -> bool
|
|
936
|
+
```
|
|
937
|
+
|
|
938
|
+
Checks if `latestExecutionStatus == 'COMPLETED'`. Refreshes details on each call.
|
|
939
|
+
|
|
940
|
+
```python
|
|
941
|
+
@property
|
|
942
|
+
def success(self) -> bool
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
Checks counts: `True` if `numbersFailed == 0` and `numbersMoved + numbersDeleted == totalNumbers`. Should only be checked after `completed` is `True`.
|
|
946
|
+
|
|
947
|
+
---
|
|
948
|
+
|
|
949
|
+
### User Move Jobs
|
|
950
|
+
|
|
951
|
+
For moving users between locations.
|
|
952
|
+
|
|
953
|
+
#### UserMoveJobList
|
|
954
|
+
|
|
955
|
+
```python
|
|
956
|
+
class UserMoveJobList(UserList):
|
|
957
|
+
def __init__(self, org: wxcadm.Org)
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
API endpoint: `v1/telephony/config/jobs/person/moveLocation`
|
|
961
|
+
|
|
962
|
+
**Methods:**
|
|
963
|
+
|
|
964
|
+
```python
|
|
965
|
+
def refresh(self) -> bool
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
```python
|
|
969
|
+
def get(self, id: str) -> Optional[UserMoveJob]
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
```python
|
|
973
|
+
def create(
|
|
974
|
+
self,
|
|
975
|
+
target_location: Location | str,
|
|
976
|
+
people: list[Person], # max 100
|
|
977
|
+
validate_only: Optional[bool] = False
|
|
978
|
+
) -> tuple[UserMoveValidationResults, UserMoveJob | None]
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
Two-phase process:
|
|
982
|
+
1. **Validation** -- validates the first user in the list. If validation fails (`errors` present), the move is not attempted.
|
|
983
|
+
2. **Move** -- if validation passes and `validate_only` is `False`, creates the actual move job.
|
|
984
|
+
|
|
985
|
+
Returns a tuple of `(UserMoveValidationResults, UserMoveJob | None)`. The job is `None` if validation failed or `validate_only` was `True`.
|
|
986
|
+
|
|
987
|
+
Raises `ValueError` if more than 100 people are provided.
|
|
988
|
+
|
|
989
|
+
#### UserMoveJob
|
|
990
|
+
|
|
991
|
+
```python
|
|
992
|
+
class UserMoveJob:
|
|
993
|
+
def __init__(self, org: wxcadm.Org, id: str, details: Optional[dict] = None)
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
**Properties:**
|
|
997
|
+
|
|
998
|
+
```python
|
|
999
|
+
@property
|
|
1000
|
+
def completed(self) -> bool
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
Checks `latestExecutionStatus == 'COMPLETED'`.
|
|
1004
|
+
|
|
1005
|
+
```python
|
|
1006
|
+
@property
|
|
1007
|
+
def success(self) -> bool
|
|
1008
|
+
```
|
|
1009
|
+
|
|
1010
|
+
Checks `failed == 0` and `moved == totalMoves`.
|
|
1011
|
+
|
|
1012
|
+
#### UserMoveValidationResults
|
|
1013
|
+
|
|
1014
|
+
```python
|
|
1015
|
+
class UserMoveValidationResults:
|
|
1016
|
+
def __init__(self)
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
**Attributes:**
|
|
1020
|
+
- `messages` (`list[dict]`) -- each dict has `severity` (`'error'` or `'impact'`), `code`, and `message`
|
|
1021
|
+
|
|
1022
|
+
**Properties:**
|
|
1023
|
+
|
|
1024
|
+
```python
|
|
1025
|
+
@property
|
|
1026
|
+
def passed(self) -> bool
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
`True` if no messages have severity `'error'`.
|
|
1030
|
+
|
|
1031
|
+
**Methods:**
|
|
1032
|
+
|
|
1033
|
+
```python
|
|
1034
|
+
def add_message(self, severity: str, code: Optional[str] = None, message: Optional[str] = None) -> bool
|
|
1035
|
+
```
|
|
1036
|
+
|
|
1037
|
+
---
|
|
1038
|
+
|
|
1039
|
+
### Rebuild Phones Jobs
|
|
1040
|
+
|
|
1041
|
+
For triggering phone configuration rebuilds at a location.
|
|
1042
|
+
|
|
1043
|
+
#### RebuildPhonesJobList
|
|
1044
|
+
|
|
1045
|
+
```python
|
|
1046
|
+
class RebuildPhonesJobList(UserList):
|
|
1047
|
+
def __init__(self, org: wxcadm.Org)
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
API endpoint: `v1/telephony/config/jobs/devices/rebuildPhones`
|
|
1051
|
+
|
|
1052
|
+
**Methods:**
|
|
1053
|
+
|
|
1054
|
+
```python
|
|
1055
|
+
def refresh(self) -> bool
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
```python
|
|
1059
|
+
def get(self, id: str) -> Optional[RebuildPhonesJob]
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
```python
|
|
1063
|
+
def create(self, location: Location | str) -> RebuildPhonesJob
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
Creates a rebuild phones job for a given location. Only location-level rebuilds are supported.
|
|
1067
|
+
|
|
1068
|
+
#### RebuildPhonesJob
|
|
1069
|
+
|
|
1070
|
+
```python
|
|
1071
|
+
class RebuildPhonesJob:
|
|
1072
|
+
def __init__(self, org: wxcadm.Org, id: str, details: Optional[dict] = None)
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
**Properties:**
|
|
1076
|
+
|
|
1077
|
+
```python
|
|
1078
|
+
@property
|
|
1079
|
+
def completed(self) -> bool
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
```python
|
|
1083
|
+
@property
|
|
1084
|
+
def device_count(self) -> int
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
Returns the number of devices included in the rebuild job.
|
|
1088
|
+
|
|
1089
|
+
`RebuildPhonesJob` does not have a `success` property unlike the other job types (`NumberManagementJob` and `UserMoveJob` both have one). The `completed` property's docstring incorrectly references a `success` attribute that was never implemented. To check success, inspect `self.details` dict directly after `completed` returns `True` (look for `deviceCount` and execution status fields).
|
|
1090
|
+
|
|
1091
|
+
---
|
|
1092
|
+
|
|
1093
|
+
## 6. Webhooks
|
|
1094
|
+
|
|
1095
|
+
Webhook management is accessed via `org.webhooks`, returning a `Webhooks` instance.
|
|
1096
|
+
|
|
1097
|
+
### Webhooks (collection)
|
|
1098
|
+
|
|
1099
|
+
```python
|
|
1100
|
+
class Webhooks(UserList):
|
|
1101
|
+
def __init__(self, org: wxcadm.Org)
|
|
1102
|
+
```
|
|
1103
|
+
|
|
1104
|
+
Fetches all webhooks from `GET /v1/webhooks` and filters to the current org.
|
|
1105
|
+
|
|
1106
|
+
Note: Uses `self.org._parent.api` (the Webex-level API) rather than `self.org.api`, because webhooks are a platform-level resource.
|
|
1107
|
+
|
|
1108
|
+
**Properties:**
|
|
1109
|
+
|
|
1110
|
+
```python
|
|
1111
|
+
@property
|
|
1112
|
+
def active(self) -> list[Webhook]
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
Returns only webhooks with status `'active'`.
|
|
1116
|
+
|
|
1117
|
+
```python
|
|
1118
|
+
@property
|
|
1119
|
+
def inactive(self) -> list[Webhook]
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
Returns only webhooks with status `'inactive'`.
|
|
1123
|
+
|
|
1124
|
+
**Methods:**
|
|
1125
|
+
|
|
1126
|
+
```python
|
|
1127
|
+
def add(
|
|
1128
|
+
self,
|
|
1129
|
+
name: str,
|
|
1130
|
+
url: str,
|
|
1131
|
+
resource: str,
|
|
1132
|
+
event: str,
|
|
1133
|
+
filter: str = None,
|
|
1134
|
+
secret: str = None,
|
|
1135
|
+
owner: str = None
|
|
1136
|
+
) -> bool
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
Creates a new webhook. See [Webex webhook docs](https://developer.webex.com/docs/webhooks) for valid `resource`, `event`, and `filter` values. Returns `True` on success, `False` otherwise.
|
|
1140
|
+
|
|
1141
|
+
### Webhook (dataclass)
|
|
1142
|
+
|
|
1143
|
+
```python
|
|
1144
|
+
@dataclass
|
|
1145
|
+
class Webhook:
|
|
1146
|
+
api: wxcadm.WebexApi
|
|
1147
|
+
orgId: str
|
|
1148
|
+
appId: str
|
|
1149
|
+
id: str
|
|
1150
|
+
name: str
|
|
1151
|
+
targetUrl: str
|
|
1152
|
+
resource: str
|
|
1153
|
+
event: str
|
|
1154
|
+
status: str # 'active' or 'inactive'
|
|
1155
|
+
created: str
|
|
1156
|
+
createdBy: str
|
|
1157
|
+
ownedBy: str
|
|
1158
|
+
filter: Optional[str] = None
|
|
1159
|
+
secret: Optional[str] = None
|
|
1160
|
+
```
|
|
1161
|
+
|
|
1162
|
+
**Methods:**
|
|
1163
|
+
|
|
1164
|
+
All update methods send a full `PUT` to `v1/webhooks/{id}` with all fields (the API requires a complete payload on update).
|
|
1165
|
+
|
|
1166
|
+
```python
|
|
1167
|
+
def delete(self) -> bool
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
Deletes the webhook.
|
|
1171
|
+
|
|
1172
|
+
```python
|
|
1173
|
+
def change_url(self, url: str) -> bool
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
Changes the target URL.
|
|
1177
|
+
|
|
1178
|
+
```python
|
|
1179
|
+
def change_name(self, name: str) -> bool
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
Changes the webhook name.
|
|
1183
|
+
|
|
1184
|
+
```python
|
|
1185
|
+
def change_secret(self, secret: str) -> bool
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
Changes the secret value for signature generation.
|
|
1189
|
+
|
|
1190
|
+
```python
|
|
1191
|
+
def change_owner(self, owner: str) -> bool
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
Changes the webhook owner.
|
|
1195
|
+
|
|
1196
|
+
```python
|
|
1197
|
+
def deactivate(self) -> bool
|
|
1198
|
+
```
|
|
1199
|
+
|
|
1200
|
+
Sets status to `'inactive'`. Returns `True` even if already inactive.
|
|
1201
|
+
|
|
1202
|
+
```python
|
|
1203
|
+
def activate(self) -> bool
|
|
1204
|
+
```
|
|
1205
|
+
|
|
1206
|
+
Sets status to `'active'`. Returns `True` even if already active.
|
|
1207
|
+
|
|
1208
|
+
---
|
|
1209
|
+
|
|
1210
|
+
## 7. wxcadm vs wxc_sdk Comparison
|
|
1211
|
+
|
|
1212
|
+
| Feature Area | wxcadm | wxc_sdk |
|
|
1213
|
+
|-------------|--------|---------|
|
|
1214
|
+
| **Trunks** | `org.call_routing.trunks` -- full CRUD, lazy detail loading | `api.telephony.prem_pstn.trunk` -- similar CRUD via Webex API |
|
|
1215
|
+
| **Route Groups** | `org.call_routing.route_groups` -- list, get, add trunk to group | `api.telephony.prem_pstn.route_group` -- full CRUD |
|
|
1216
|
+
| **Route Lists** | `org.call_routing.route_lists` -- list, get, create (no delete) | `api.telephony.prem_pstn.route_list` -- full CRUD including delete |
|
|
1217
|
+
| **Dial Plans** | `org.call_routing.dial_plans` -- list, pattern add/delete (no collection `get()`) | `api.telephony.prem_pstn.dial_plan` -- full CRUD |
|
|
1218
|
+
| **Translation Patterns** | `TranslationPatternList` -- org or location scope, full CRUD | `api.telephony.call_routing.tp` -- similar scope and CRUD |
|
|
1219
|
+
| **Call Routing Test** | `org.call_routing.test()` | `api.telephony.test_call_routing()` |
|
|
1220
|
+
| **PSTN** | `LocationPSTN` -- get/set provider per location | Covered under location telephony settings |
|
|
1221
|
+
| **CDR** | `CallDetailRecords` -- post-processing class, records passed in externally | No direct equivalent; CDRs obtained via reports or analytics API |
|
|
1222
|
+
| **Reports** | `ReportList` -- template-based report creation with `cdr_report()` shortcut | `api.reports` -- similar template-based approach |
|
|
1223
|
+
| **Jobs (Number Move)** | `NumberManagementJobList` -- move only, single number limit | `api.telephony.jobs.manage_numbers` -- similar |
|
|
1224
|
+
| **Jobs (User Move)** | `UserMoveJobList` -- validate-then-move pattern, max 100 users | `api.telephony.jobs.move_users` -- similar |
|
|
1225
|
+
| **Jobs (Rebuild Phones)** | `RebuildPhonesJobList` -- location-level only | `api.telephony.jobs.rebuild_phones` -- similar |
|
|
1226
|
+
| **Webhooks** | `Webhooks` -- full CRUD with activate/deactivate | `api.webhook` -- full CRUD |
|
|
1227
|
+
|
|
1228
|
+
**Key architectural differences:**
|
|
1229
|
+
|
|
1230
|
+
- **wxcadm** uses `UserList` subclasses throughout, so collections are iterable lists that also have `.get()` methods. Properties often trigger API calls on access (lazy loading).
|
|
1231
|
+
- **wxc_sdk** uses explicit list/get/create/update/delete methods on API wrapper classes. Data is returned as typed dataclass models.
|
|
1232
|
+
- **wxcadm CDR processing** is unique -- it builds a `Call -> CallLeg -> LegPart` hierarchy from raw CSV records with automatic transfer merging. wxc_sdk does not have an equivalent post-processing layer.
|
|
1233
|
+
- **wxcadm job validation** (particularly `UserMoveJobList.create`) performs a two-phase validate-then-execute pattern in a single method call, returning both validation results and the job. wxc_sdk typically separates these concerns.
|
|
1234
|
+
|
|
1235
|
+
---
|
|
1236
|
+
|
|
1237
|
+
## API Endpoint Summary
|
|
1238
|
+
|
|
1239
|
+
| Module | Endpoint Pattern |
|
|
1240
|
+
|--------|-----------------|
|
|
1241
|
+
| Trunks | `v1/telephony/config/premisePstn/trunks` |
|
|
1242
|
+
| Route Groups | `v1/telephony/config/premisePstn/routeGroups` |
|
|
1243
|
+
| Route Lists | `v1/telephony/config/premisePstn/routeLists` |
|
|
1244
|
+
| Dial Plans | `v1/telephony/config/premisePstn/dialPlans` |
|
|
1245
|
+
| Translation Patterns | `v1/telephony/config/callRouting/translationPatterns` |
|
|
1246
|
+
| Translation Patterns (location) | `v1/telephony/config/locations/{id}/callRouting/translationPatterns` |
|
|
1247
|
+
| Call Routing Test | `v1/telephony/config/actions/testCallRouting/invoke` |
|
|
1248
|
+
| PSTN Connection | `v1/telephony/pstn/locations/{id}/connection` |
|
|
1249
|
+
| PSTN Connection Options | `v1/telephony/pstn/locations/{id}/connectionOptions` |
|
|
1250
|
+
| Reports | `v1/reports` |
|
|
1251
|
+
| Report Templates | `v1/report/templates` |
|
|
1252
|
+
| Number Move Jobs | `v1/telephony/config/jobs/numbers/manageNumbers` |
|
|
1253
|
+
| User Move Jobs | `v1/telephony/config/jobs/person/moveLocation` |
|
|
1254
|
+
| Rebuild Phones Jobs | `v1/telephony/config/jobs/devices/rebuildPhones` |
|
|
1255
|
+
| Webhooks | `v1/webhooks` |
|
|
1256
|
+
|
|
1257
|
+
---
|
|
1258
|
+
|
|
1259
|
+
## See Also
|
|
1260
|
+
|
|
1261
|
+
- [call-routing.md](call-routing.md) — wxc_sdk call routing APIs (trunks, route groups, route lists, dial plans, translation patterns)
|
|
1262
|
+
- [reporting-analytics.md](reporting-analytics.md) — wxc_sdk reporting and CDR access patterns for comparison with wxcadm's CDR post-processing
|