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,194 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import typer
|
|
3
|
+
from wxcli.auth import get_api
|
|
4
|
+
from wxcli.errors import WebexError, handle_rest_error
|
|
5
|
+
from wxcli.output import print_table, print_json
|
|
6
|
+
from wxcli.config import resolve_org_id, get_cc_base_url, get_cc_org_id
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Manage Webex Contact Center cc-callbacks.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("list")
|
|
13
|
+
def cmd_list(
|
|
14
|
+
callback_number: str = typer.Option(None, "--callback-number", help="The callback customer number to filter the scheduled callbac"),
|
|
15
|
+
assignee_agent: str = typer.Option(None, "--assignee-agent", help="The unique identifier of the agent assigned to handle the ca"),
|
|
16
|
+
page: str = typer.Option(None, "--page", help="The page number to retrieve."),
|
|
17
|
+
page_size: str = typer.Option(None, "--page-size", help="The number of items per page."),
|
|
18
|
+
sort_by: str = typer.Option(None, "--sort-by", help="Choices: customerName, scheduledTime, assignedTime"),
|
|
19
|
+
sort_order: str = typer.Option(None, "--sort-order", help="Choices: asc, desc"),
|
|
20
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
21
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
22
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
23
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
24
|
+
):
|
|
25
|
+
"""Get scheduled callbacks."""
|
|
26
|
+
api = get_api(debug=debug)
|
|
27
|
+
cc_base_url = get_cc_base_url()
|
|
28
|
+
org_id = get_cc_org_id(api.session)
|
|
29
|
+
url = f"{cc_base_url}/callbacks/organization/{org_id}/scheduled-callback"
|
|
30
|
+
params = {}
|
|
31
|
+
if callback_number is not None:
|
|
32
|
+
params["callbackNumber"] = callback_number
|
|
33
|
+
if assignee_agent is not None:
|
|
34
|
+
params["assigneeAgent"] = assignee_agent
|
|
35
|
+
if page is not None:
|
|
36
|
+
params["page"] = page
|
|
37
|
+
if page_size is not None:
|
|
38
|
+
params["pageSize"] = page_size
|
|
39
|
+
if sort_by is not None:
|
|
40
|
+
params["sortBy"] = sort_by
|
|
41
|
+
if sort_order is not None:
|
|
42
|
+
params["sortOrder"] = sort_order
|
|
43
|
+
if limit > 0:
|
|
44
|
+
params["max"] = limit
|
|
45
|
+
if offset > 0:
|
|
46
|
+
params["start"] = offset
|
|
47
|
+
result = None
|
|
48
|
+
try:
|
|
49
|
+
result = api.session.rest_get(url, params=params)
|
|
50
|
+
except WebexError as e:
|
|
51
|
+
handle_rest_error(e)
|
|
52
|
+
result = result or []
|
|
53
|
+
items = result.get("data", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
54
|
+
if output == "json":
|
|
55
|
+
print_json(items)
|
|
56
|
+
else:
|
|
57
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@app.command("create")
|
|
62
|
+
def create(
|
|
63
|
+
customer_name: str = typer.Option(None, "--customer-name", help="(required) Name of the Customer for which callback has to be scheduled."),
|
|
64
|
+
callback_number: str = typer.Option(None, "--callback-number", help="(required) Customer's phone number for the callback. Allows an optional"),
|
|
65
|
+
timezone: str = typer.Option(None, "--timezone", help="(required) Valid IANA timezone name"),
|
|
66
|
+
schedule_date: str = typer.Option(None, "--schedule-date", help="(required) Scheduled date in ISO-8601 (YYYY-MM-DD) format. This must be"),
|
|
67
|
+
start_time: str = typer.Option(None, "--start-time", help="(required) Scheduled start time in ISO-8601 (HH:mm:ss) format. Start ti"),
|
|
68
|
+
end_time: str = typer.Option(None, "--end-time", help="(required) Scheduled end time in ISO-8601 (HH:mm:ss) format. End time m"),
|
|
69
|
+
queue_id: str = typer.Option(None, "--queue-id", help="(required) Unique identifier for the queue to which the callback is ass"),
|
|
70
|
+
callback_reason: str = typer.Option(None, "--callback-reason", help="Reason for the callback request. This is optional and can be"),
|
|
71
|
+
source_interaction: str = typer.Option(None, "--source-interaction", help="Source interaction ID for the callback. This is optional and"),
|
|
72
|
+
assignee_agent: str = typer.Option(None, "--assignee-agent", help="The unique identifier of the specific agent (CI userId), who"),
|
|
73
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
74
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
75
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
76
|
+
):
|
|
77
|
+
"""Schedule a Callback."""
|
|
78
|
+
api = get_api(debug=debug)
|
|
79
|
+
cc_base_url = get_cc_base_url()
|
|
80
|
+
org_id = get_cc_org_id(api.session)
|
|
81
|
+
url = f"{cc_base_url}/callbacks/organization/{org_id}/scheduled-callback"
|
|
82
|
+
if json_body:
|
|
83
|
+
body = json.loads(json_body)
|
|
84
|
+
else:
|
|
85
|
+
body = {}
|
|
86
|
+
if customer_name is not None:
|
|
87
|
+
body["customerName"] = customer_name
|
|
88
|
+
if callback_number is not None:
|
|
89
|
+
body["callbackNumber"] = callback_number
|
|
90
|
+
if timezone is not None:
|
|
91
|
+
body["timezone"] = timezone
|
|
92
|
+
if schedule_date is not None:
|
|
93
|
+
body["scheduleDate"] = schedule_date
|
|
94
|
+
if start_time is not None:
|
|
95
|
+
body["startTime"] = start_time
|
|
96
|
+
if end_time is not None:
|
|
97
|
+
body["endTime"] = end_time
|
|
98
|
+
if queue_id is not None:
|
|
99
|
+
body["queueId"] = queue_id
|
|
100
|
+
if callback_reason is not None:
|
|
101
|
+
body["callbackReason"] = callback_reason
|
|
102
|
+
if source_interaction is not None:
|
|
103
|
+
body["sourceInteraction"] = source_interaction
|
|
104
|
+
if assignee_agent is not None:
|
|
105
|
+
body["assigneeAgent"] = assignee_agent
|
|
106
|
+
_missing = [f for f in ['customerName', 'callbackNumber', 'timezone', 'scheduleDate', 'startTime', 'endTime', 'queueId'] if f not in body or body[f] is None]
|
|
107
|
+
if _missing:
|
|
108
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
109
|
+
raise typer.Exit(1)
|
|
110
|
+
try:
|
|
111
|
+
result = api.session.rest_post(url, json=body)
|
|
112
|
+
except WebexError as e:
|
|
113
|
+
handle_rest_error(e)
|
|
114
|
+
if output == "json":
|
|
115
|
+
print_json(result)
|
|
116
|
+
elif isinstance(result, dict) and "id" in result:
|
|
117
|
+
typer.echo(f"Created: {result['id']}")
|
|
118
|
+
elif not result or result == {}:
|
|
119
|
+
typer.echo("Created.")
|
|
120
|
+
else:
|
|
121
|
+
print_json(result)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@app.command("show")
|
|
126
|
+
def show(
|
|
127
|
+
id: str = typer.Argument(help="id"),
|
|
128
|
+
output: str = typer.Option("json", "--output", "-o", help="Output format: table|json"),
|
|
129
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
130
|
+
):
|
|
131
|
+
"""Get scheduled callback by Id."""
|
|
132
|
+
api = get_api(debug=debug)
|
|
133
|
+
cc_base_url = get_cc_base_url()
|
|
134
|
+
org_id = get_cc_org_id(api.session)
|
|
135
|
+
url = f"{cc_base_url}/callbacks/organization/{org_id}/scheduled-callback/{id}"
|
|
136
|
+
try:
|
|
137
|
+
result = api.session.rest_get(url)
|
|
138
|
+
except WebexError as e:
|
|
139
|
+
handle_rest_error(e)
|
|
140
|
+
if output == "json":
|
|
141
|
+
print_json(result)
|
|
142
|
+
else:
|
|
143
|
+
if isinstance(result, dict):
|
|
144
|
+
print_table([result], columns=[("Key", ""), ("Value", "")], limit=0)
|
|
145
|
+
elif isinstance(result, list):
|
|
146
|
+
print_table(result, columns=[("ID", "id"), ("Name", "name")], limit=0)
|
|
147
|
+
else:
|
|
148
|
+
print_json(result)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@app.command("update")
|
|
153
|
+
def update(
|
|
154
|
+
id: str = typer.Argument(help="id"),
|
|
155
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
156
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
157
|
+
):
|
|
158
|
+
"""Update scheduled callback by Id."""
|
|
159
|
+
api = get_api(debug=debug)
|
|
160
|
+
cc_base_url = get_cc_base_url()
|
|
161
|
+
org_id = get_cc_org_id(api.session)
|
|
162
|
+
url = f"{cc_base_url}/callbacks/organization/{org_id}/scheduled-callback/{id}"
|
|
163
|
+
if json_body:
|
|
164
|
+
body = json.loads(json_body)
|
|
165
|
+
else:
|
|
166
|
+
body = {}
|
|
167
|
+
try:
|
|
168
|
+
result = api.session.rest_put(url, json=body)
|
|
169
|
+
except WebexError as e:
|
|
170
|
+
handle_rest_error(e)
|
|
171
|
+
typer.echo(f"Updated.")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@app.command("delete")
|
|
176
|
+
def delete(
|
|
177
|
+
id: str = typer.Argument(help="id"),
|
|
178
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
179
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
180
|
+
):
|
|
181
|
+
"""Delete scheduled callback by Id."""
|
|
182
|
+
if not force:
|
|
183
|
+
typer.confirm(f"Delete {id}?", abort=True)
|
|
184
|
+
api = get_api(debug=debug)
|
|
185
|
+
cc_base_url = get_cc_base_url()
|
|
186
|
+
org_id = get_cc_org_id(api.session)
|
|
187
|
+
url = f"{cc_base_url}/callbacks/organization/{org_id}/scheduled-callback/{id}"
|
|
188
|
+
try:
|
|
189
|
+
api.session.rest_delete(url)
|
|
190
|
+
except WebexError as e:
|
|
191
|
+
handle_rest_error(e)
|
|
192
|
+
typer.echo(f"Deleted: {id}")
|
|
193
|
+
|
|
194
|
+
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import typer
|
|
3
|
+
from wxcli.auth import get_api
|
|
4
|
+
from wxcli.errors import WebexError, handle_rest_error
|
|
5
|
+
from wxcli.output import print_table, print_json
|
|
6
|
+
from wxcli.config import resolve_org_id, get_cc_base_url, get_cc_org_id
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Manage Webex Contact Center cc-campaign.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("create")
|
|
13
|
+
def create(
|
|
14
|
+
id_param: str = typer.Option(None, "--id", help="(required) The id represents the unique id with which the Campaign Requ"),
|
|
15
|
+
vendor_version: str = typer.Option(None, "--vendor-version", help="(required) Vendor specific information, maximum length 32 characters."),
|
|
16
|
+
campaign_type: str = typer.Option(None, "--campaign-type", help="(required) Type of campaign and campaignType should be one of \"progress"),
|
|
17
|
+
campaign_name: str = typer.Option(None, "--campaign-name", help="(Optional) Used if different than id, maximum length 64 char"),
|
|
18
|
+
auth_token: str = typer.Option(None, "--auth-token", help="(Not in use) The token needed by the dialer for querying rec"),
|
|
19
|
+
dialing_rate: str = typer.Option(None, "--dialing-rate", help="(required) Number of contacts to be dialed out per available Agent. For"),
|
|
20
|
+
entry_point_id: str = typer.Option(None, "--entry-point-id", help="(required) Webex Contact Center outdial entry point, maximum length 36"),
|
|
21
|
+
dialing_list_fetch_url: str = typer.Option(None, "--dialing-list-fetch-url", help="(required) URL the dialer will use to fetch the list of contacts to dia"),
|
|
22
|
+
outdial_ani: str = typer.Option(None, "--outdial-ani", help="(required) The ANI (E164) that will be presented to the customer. Thes"),
|
|
23
|
+
record_count: str = typer.Option(None, "--record-count", help="(required) Value to indicate the recordCount the Campaign Manager expec"),
|
|
24
|
+
no_answer_ring_limit: str = typer.Option(None, "--no-answer-ring-limit", help="(Optional) Number of seconds before a dialed call from the d"),
|
|
25
|
+
max_dialing_rate: str = typer.Option(None, "--max-dialing-rate", help="Caps the maximum dialing rate per agent at this value. The r"),
|
|
26
|
+
abandon_rate_percentage: str = typer.Option(None, "--abandon-rate-percentage", help="The percentage of calls that are allowed to be abandoned. Th"),
|
|
27
|
+
predictive_correction_pace: str = typer.Option(None, "--predictive-correction-pace", help="A count of the number of live voice connections that must oc"),
|
|
28
|
+
predictive_gain: str = typer.Option(None, "--predictive-gain", help="The size of the adjustment to lines per agent each time an a"),
|
|
29
|
+
reservation_percentage: str = typer.Option(None, "--reservation-percentage", help="(Not in use) The percentage of agents to reserve within the"),
|
|
30
|
+
ivr_ports: str = typer.Option(None, "--ivr-ports", help="The number of IVR ports to use for this campaign. IVR ports"),
|
|
31
|
+
preview_offer_timeout: str = typer.Option(None, "--preview-offer-timeout", help="(Required if previewOfferTimeoutAutoAction is provided, opti"),
|
|
32
|
+
preview_offer_timeout_auto_action: str = typer.Option(None, "--preview-offer-timeout-auto-action", help="(Required if previewOfferTimeout is provided, optional other"),
|
|
33
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
34
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
35
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
36
|
+
):
|
|
37
|
+
"""Start Campaign Request\n\nExample --json-body:\n '{"id":"...","vendorVersion":"...","campaignType":"...","dialingRate":0,"entryPointId":"...","dialingListFetchURL":"...","outdialANI":"...","recordCount":0}'."""
|
|
38
|
+
api = get_api(debug=debug)
|
|
39
|
+
cc_base_url = get_cc_base_url()
|
|
40
|
+
url = f"{cc_base_url}/dialer/campaign"
|
|
41
|
+
if json_body:
|
|
42
|
+
body = json.loads(json_body)
|
|
43
|
+
else:
|
|
44
|
+
body = {}
|
|
45
|
+
if id_param is not None:
|
|
46
|
+
body["id"] = id_param
|
|
47
|
+
if vendor_version is not None:
|
|
48
|
+
body["vendorVersion"] = vendor_version
|
|
49
|
+
if campaign_type is not None:
|
|
50
|
+
body["campaignType"] = campaign_type
|
|
51
|
+
if campaign_name is not None:
|
|
52
|
+
body["campaignName"] = campaign_name
|
|
53
|
+
if auth_token is not None:
|
|
54
|
+
body["authToken"] = auth_token
|
|
55
|
+
if dialing_rate is not None:
|
|
56
|
+
body["dialingRate"] = dialing_rate
|
|
57
|
+
if entry_point_id is not None:
|
|
58
|
+
body["entryPointId"] = entry_point_id
|
|
59
|
+
if dialing_list_fetch_url is not None:
|
|
60
|
+
body["dialingListFetchURL"] = dialing_list_fetch_url
|
|
61
|
+
if outdial_ani is not None:
|
|
62
|
+
body["outdialANI"] = outdial_ani
|
|
63
|
+
if record_count is not None:
|
|
64
|
+
body["recordCount"] = record_count
|
|
65
|
+
if no_answer_ring_limit is not None:
|
|
66
|
+
body["noAnswerRingLimit"] = no_answer_ring_limit
|
|
67
|
+
if max_dialing_rate is not None:
|
|
68
|
+
body["maxDialingRate"] = max_dialing_rate
|
|
69
|
+
if abandon_rate_percentage is not None:
|
|
70
|
+
body["abandonRatePercentage"] = abandon_rate_percentage
|
|
71
|
+
if predictive_correction_pace is not None:
|
|
72
|
+
body["predictiveCorrectionPace"] = predictive_correction_pace
|
|
73
|
+
if predictive_gain is not None:
|
|
74
|
+
body["predictiveGain"] = predictive_gain
|
|
75
|
+
if reservation_percentage is not None:
|
|
76
|
+
body["reservationPercentage"] = reservation_percentage
|
|
77
|
+
if ivr_ports is not None:
|
|
78
|
+
body["ivrPorts"] = ivr_ports
|
|
79
|
+
if preview_offer_timeout is not None:
|
|
80
|
+
body["previewOfferTimeout"] = preview_offer_timeout
|
|
81
|
+
if preview_offer_timeout_auto_action is not None:
|
|
82
|
+
body["previewOfferTimeoutAutoAction"] = preview_offer_timeout_auto_action
|
|
83
|
+
_missing = [f for f in ['id', 'vendorVersion', 'campaignType', 'dialingRate', 'entryPointId', 'dialingListFetchURL', 'outdialANI', 'recordCount'] if f not in body or body[f] is None]
|
|
84
|
+
if _missing:
|
|
85
|
+
typer.echo("Error: Missing required fields: " + ", ".join(_missing), err=True)
|
|
86
|
+
raise typer.Exit(1)
|
|
87
|
+
try:
|
|
88
|
+
result = api.session.rest_post(url, json=body)
|
|
89
|
+
except WebexError as e:
|
|
90
|
+
handle_rest_error(e)
|
|
91
|
+
if output == "json":
|
|
92
|
+
print_json(result)
|
|
93
|
+
elif isinstance(result, dict) and "id" in result:
|
|
94
|
+
typer.echo(f"Created: {result['id']}")
|
|
95
|
+
elif not result or result == {}:
|
|
96
|
+
typer.echo("Created.")
|
|
97
|
+
else:
|
|
98
|
+
print_json(result)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@app.command("list")
|
|
103
|
+
def cmd_list(
|
|
104
|
+
campaign_id: str = typer.Option(..., "--campaign-id", help="The campaign ID for which valid campaign times are being req"),
|
|
105
|
+
agent_id: str = typer.Option(..., "--agent-id", help="The agent ID for whom valid campaign times are being request"),
|
|
106
|
+
tracking_id: str = typer.Option(None, "--tracking-id", help="Optional tracking identifier for request tracing."),
|
|
107
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
108
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
109
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
110
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
111
|
+
):
|
|
112
|
+
"""Get Valid Campaign Times."""
|
|
113
|
+
api = get_api(debug=debug)
|
|
114
|
+
cc_base_url = get_cc_base_url()
|
|
115
|
+
org_id = get_cc_org_id(api.session)
|
|
116
|
+
url = f"{cc_base_url}/organization/{org_id}/getValidCampaignTimes"
|
|
117
|
+
params = {}
|
|
118
|
+
if campaign_id is not None:
|
|
119
|
+
params["campaignId"] = campaign_id
|
|
120
|
+
if agent_id is not None:
|
|
121
|
+
params["agentId"] = agent_id
|
|
122
|
+
if tracking_id is not None:
|
|
123
|
+
params["trackingId"] = tracking_id
|
|
124
|
+
if limit > 0:
|
|
125
|
+
params["max"] = limit
|
|
126
|
+
if offset > 0:
|
|
127
|
+
params["start"] = offset
|
|
128
|
+
result = None
|
|
129
|
+
try:
|
|
130
|
+
result = api.session.rest_get(url, params=params)
|
|
131
|
+
except WebexError as e:
|
|
132
|
+
handle_rest_error(e)
|
|
133
|
+
result = result or []
|
|
134
|
+
items = result.get("items", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
135
|
+
if output == "json":
|
|
136
|
+
print_json(items)
|
|
137
|
+
else:
|
|
138
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
@app.command("update")
|
|
143
|
+
def update(
|
|
144
|
+
campaign_id: str = typer.Argument(help="campaignId"),
|
|
145
|
+
dialing_rate: str = typer.Option(None, "--dialing-rate", help="Number of contacts to be dialed out per available Agent. For"),
|
|
146
|
+
campaign_name: str = typer.Option(None, "--campaign-name", help="(Optional) Used if different than id, maximum length 64 char"),
|
|
147
|
+
auth_token: str = typer.Option(None, "--auth-token", help="(Not in use) The token needed by the dialer for querying rec"),
|
|
148
|
+
dialing_list_fetch_url: str = typer.Option(None, "--dialing-list-fetch-url", help="URL the dialer will use to fetch the list of contacts to dia"),
|
|
149
|
+
outdial_ani: str = typer.Option(None, "--outdial-ani", help="The ANI (E164) that will be presented to the customer. Thes"),
|
|
150
|
+
no_answer_ring_limit: str = typer.Option(None, "--no-answer-ring-limit", help="(Optional) Number of seconds before a dialed call from the d"),
|
|
151
|
+
max_dialing_rate: str = typer.Option(None, "--max-dialing-rate", help="Caps the maximum dialing rate per agent at this value. The r"),
|
|
152
|
+
reservation_percentage: str = typer.Option(None, "--reservation-percentage", help="(Not in use) The percentage of agents to reserve within the"),
|
|
153
|
+
preview_offer_timeout: str = typer.Option(None, "--preview-offer-timeout", help="(Required only if previewOfferTimeoutAutoAction is provided)"),
|
|
154
|
+
preview_offer_timeout_auto_action: str = typer.Option(None, "--preview-offer-timeout-auto-action", help="(Required only if previewOfferTimeout is provided) The autom"),
|
|
155
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
156
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
157
|
+
):
|
|
158
|
+
"""Update Campaign Request\n\nExample --json-body:\n '{"dialingRate":0,"dialingListFetchURL":"...","outdialANI":"...","campaignName":"...","authToken":"...","noAnswerRingLimit":0,"maxDialingRate":0,"reservationPercentage":0}'."""
|
|
159
|
+
api = get_api(debug=debug)
|
|
160
|
+
cc_base_url = get_cc_base_url()
|
|
161
|
+
url = f"{cc_base_url}/dialer/campaign/{campaign_id}"
|
|
162
|
+
if json_body:
|
|
163
|
+
body = json.loads(json_body)
|
|
164
|
+
else:
|
|
165
|
+
body = {}
|
|
166
|
+
if dialing_rate is not None:
|
|
167
|
+
body["dialingRate"] = dialing_rate
|
|
168
|
+
if campaign_name is not None:
|
|
169
|
+
body["campaignName"] = campaign_name
|
|
170
|
+
if auth_token is not None:
|
|
171
|
+
body["authToken"] = auth_token
|
|
172
|
+
if dialing_list_fetch_url is not None:
|
|
173
|
+
body["dialingListFetchURL"] = dialing_list_fetch_url
|
|
174
|
+
if outdial_ani is not None:
|
|
175
|
+
body["outdialANI"] = outdial_ani
|
|
176
|
+
if no_answer_ring_limit is not None:
|
|
177
|
+
body["noAnswerRingLimit"] = no_answer_ring_limit
|
|
178
|
+
if max_dialing_rate is not None:
|
|
179
|
+
body["maxDialingRate"] = max_dialing_rate
|
|
180
|
+
if reservation_percentage is not None:
|
|
181
|
+
body["reservationPercentage"] = reservation_percentage
|
|
182
|
+
if preview_offer_timeout is not None:
|
|
183
|
+
body["previewOfferTimeout"] = preview_offer_timeout
|
|
184
|
+
if preview_offer_timeout_auto_action is not None:
|
|
185
|
+
body["previewOfferTimeoutAutoAction"] = preview_offer_timeout_auto_action
|
|
186
|
+
try:
|
|
187
|
+
result = api.session.rest_put(url, json=body)
|
|
188
|
+
except WebexError as e:
|
|
189
|
+
handle_rest_error(e)
|
|
190
|
+
typer.echo(f"Updated.")
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@app.command("delete")
|
|
195
|
+
def delete(
|
|
196
|
+
campaign_id: str = typer.Argument(help="campaignId"),
|
|
197
|
+
force: bool = typer.Option(False, "--force", help="Skip confirmation"),
|
|
198
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
199
|
+
):
|
|
200
|
+
"""Stop Campaign Request."""
|
|
201
|
+
if not force:
|
|
202
|
+
typer.confirm(f"Delete {campaign_id}?", abort=True)
|
|
203
|
+
api = get_api(debug=debug)
|
|
204
|
+
cc_base_url = get_cc_base_url()
|
|
205
|
+
url = f"{cc_base_url}/dialer/campaign/{campaign_id}"
|
|
206
|
+
try:
|
|
207
|
+
api.session.rest_delete(url)
|
|
208
|
+
except WebexError as e:
|
|
209
|
+
handle_rest_error(e)
|
|
210
|
+
typer.echo(f"Deleted: {campaign_id}")
|
|
211
|
+
|
|
212
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import typer
|
|
3
|
+
from wxcli.auth import get_api
|
|
4
|
+
from wxcli.errors import WebexError, handle_rest_error
|
|
5
|
+
from wxcli.output import print_table, print_json
|
|
6
|
+
from wxcli.config import get_cc_base_url
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Manage Webex Contact Center cc-captures.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("create")
|
|
13
|
+
def create(
|
|
14
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
15
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
16
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
17
|
+
):
|
|
18
|
+
"""List Captures\n\nExample --json-body:\n '{"query":{"taskIds":["..."],"orgId":"...","urlExpiration":0,"includeSegments":true,"includeVARecordings":true,"includeScreenRecordings":true}}'."""
|
|
19
|
+
api = get_api(debug=debug)
|
|
20
|
+
cc_base_url = get_cc_base_url()
|
|
21
|
+
url = f"{cc_base_url}/captures/query"
|
|
22
|
+
if json_body:
|
|
23
|
+
body = json.loads(json_body)
|
|
24
|
+
else:
|
|
25
|
+
body = {}
|
|
26
|
+
try:
|
|
27
|
+
result = api.session.rest_post(url, json=body)
|
|
28
|
+
except WebexError as e:
|
|
29
|
+
handle_rest_error(e)
|
|
30
|
+
if output == "json":
|
|
31
|
+
print_json(result)
|
|
32
|
+
elif isinstance(result, dict) and "id" in result:
|
|
33
|
+
typer.echo(f"Created: {result['id']}")
|
|
34
|
+
elif not result or result == {}:
|
|
35
|
+
typer.echo("Created.")
|
|
36
|
+
else:
|
|
37
|
+
print_json(result)
|
|
38
|
+
|
|
39
|
+
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import typer
|
|
3
|
+
from wxcli.auth import get_api
|
|
4
|
+
from wxcli.errors import WebexError, handle_rest_error
|
|
5
|
+
from wxcli.output import print_table, print_json
|
|
6
|
+
from wxcli.config import get_cc_base_url
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Manage Webex Contact Center cc-contact-list.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("create")
|
|
13
|
+
def create(
|
|
14
|
+
campaign_id: str = typer.Argument(help="campaignId"),
|
|
15
|
+
activation_time_lag_minutes: str = typer.Option(None, "--activation-time-lag-minutes", help="Contact list activation time lag in minutes (0 = immediate a"),
|
|
16
|
+
activation_date_time: str = typer.Option(None, "--activation-date-time", help="Contact list activation DateTimeStamp (format: YYYY-MM-DDTHH"),
|
|
17
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
18
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
19
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
20
|
+
):
|
|
21
|
+
"""Create contact list\n\nExample --json-body:\n '{"supportedChannels":["Voice"],"activationTimeLagMinutes":0,"activationDateTime":"..."}'."""
|
|
22
|
+
api = get_api(debug=debug)
|
|
23
|
+
cc_base_url = get_cc_base_url()
|
|
24
|
+
url = f"{cc_base_url}/v3/campaign-management/campaigns/{campaign_id}/contact-list"
|
|
25
|
+
if json_body:
|
|
26
|
+
body = json.loads(json_body)
|
|
27
|
+
else:
|
|
28
|
+
body = {}
|
|
29
|
+
if activation_time_lag_minutes is not None:
|
|
30
|
+
body["activationTimeLagMinutes"] = activation_time_lag_minutes
|
|
31
|
+
if activation_date_time is not None:
|
|
32
|
+
body["activationDateTime"] = activation_date_time
|
|
33
|
+
try:
|
|
34
|
+
result = api.session.rest_post(url, json=body)
|
|
35
|
+
except WebexError as e:
|
|
36
|
+
handle_rest_error(e)
|
|
37
|
+
if output == "json":
|
|
38
|
+
print_json(result)
|
|
39
|
+
elif isinstance(result, dict) and "contactListId" in result:
|
|
40
|
+
typer.echo(f"Created: {result['contactListId']}")
|
|
41
|
+
elif isinstance(result, dict) and "id" in result:
|
|
42
|
+
typer.echo(f"Created: {result['id']}")
|
|
43
|
+
elif not result or result == {}:
|
|
44
|
+
typer.echo("Created.")
|
|
45
|
+
else:
|
|
46
|
+
print_json(result)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@app.command("create-contacts")
|
|
51
|
+
def create_contacts(
|
|
52
|
+
campaign_id: str = typer.Argument(help="campaignId"),
|
|
53
|
+
contact_list_id: str = typer.Argument(help="contactListId"),
|
|
54
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
55
|
+
output: str = typer.Option("id", "--output", "-o", help="Output format: id|json"),
|
|
56
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
57
|
+
):
|
|
58
|
+
"""Create contacts within a contact list\n\nExample --json-body:\n '{"contacts":[{"contactAttributes":"..."}]}'."""
|
|
59
|
+
api = get_api(debug=debug)
|
|
60
|
+
cc_base_url = get_cc_base_url()
|
|
61
|
+
url = f"{cc_base_url}/v3/campaign-management/campaigns/{campaign_id}/contact-list/{contact_list_id}/contacts"
|
|
62
|
+
if json_body:
|
|
63
|
+
body = json.loads(json_body)
|
|
64
|
+
else:
|
|
65
|
+
body = {}
|
|
66
|
+
try:
|
|
67
|
+
result = api.session.rest_post(url, json=body)
|
|
68
|
+
except WebexError as e:
|
|
69
|
+
handle_rest_error(e)
|
|
70
|
+
if output == "json":
|
|
71
|
+
print_json(result)
|
|
72
|
+
elif isinstance(result, dict) and "id" in result:
|
|
73
|
+
typer.echo(f"Created: {result['id']}")
|
|
74
|
+
elif not result or result == {}:
|
|
75
|
+
typer.echo("Created.")
|
|
76
|
+
else:
|
|
77
|
+
print_json(result)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@app.command("update")
|
|
82
|
+
def update(
|
|
83
|
+
campaign_id: str = typer.Argument(help="campaignId"),
|
|
84
|
+
contact_list_id: str = typer.Argument(help="contactListId"),
|
|
85
|
+
contact_id: str = typer.Argument(help="contactId"),
|
|
86
|
+
contact_status: str = typer.Option(None, "--contact-status", help="Choices: CLOSED"),
|
|
87
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
88
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
89
|
+
):
|
|
90
|
+
"""Update a contact's status within a contact list."""
|
|
91
|
+
api = get_api(debug=debug)
|
|
92
|
+
cc_base_url = get_cc_base_url()
|
|
93
|
+
url = f"{cc_base_url}/v3/campaign-management/campaigns/{campaign_id}/contact-list/{contact_list_id}/contacts/{contact_id}"
|
|
94
|
+
if json_body:
|
|
95
|
+
body = json.loads(json_body)
|
|
96
|
+
else:
|
|
97
|
+
body = {}
|
|
98
|
+
if contact_status is not None:
|
|
99
|
+
body["contactStatus"] = contact_status
|
|
100
|
+
try:
|
|
101
|
+
result = api.session.rest_patch(url, json=body)
|
|
102
|
+
except WebexError as e:
|
|
103
|
+
handle_rest_error(e)
|
|
104
|
+
typer.echo(f"Updated.")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@app.command("update-status")
|
|
109
|
+
def update_status(
|
|
110
|
+
campaign_id: str = typer.Argument(help="campaignId"),
|
|
111
|
+
contact_list_id: str = typer.Argument(help="contactListId"),
|
|
112
|
+
contact_list_status: str = typer.Option(None, "--contact-list-status", help="Contact List Status (e.g., EXPIRED). Note: This value is not"),
|
|
113
|
+
json_body: str = typer.Option(None, "--json-body", help="Full JSON body (overrides other options)"),
|
|
114
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
115
|
+
):
|
|
116
|
+
"""Update contact list status."""
|
|
117
|
+
api = get_api(debug=debug)
|
|
118
|
+
cc_base_url = get_cc_base_url()
|
|
119
|
+
url = f"{cc_base_url}/v3/campaign-management/campaigns/{campaign_id}/contact-list/{contact_list_id}/status"
|
|
120
|
+
if json_body:
|
|
121
|
+
body = json.loads(json_body)
|
|
122
|
+
else:
|
|
123
|
+
body = {}
|
|
124
|
+
if contact_list_status is not None:
|
|
125
|
+
body["contactListStatus"] = contact_list_status
|
|
126
|
+
try:
|
|
127
|
+
result = api.session.rest_patch(url, json=body)
|
|
128
|
+
except WebexError as e:
|
|
129
|
+
handle_rest_error(e)
|
|
130
|
+
typer.echo(f"Updated.")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@app.command("list")
|
|
135
|
+
def cmd_list(
|
|
136
|
+
campaign_id: str = typer.Argument(help="campaignId"),
|
|
137
|
+
status: str = typer.Option(None, "--status", help="Choices: Active, Expired, UploadFailed"),
|
|
138
|
+
source: str = typer.Option(None, "--source", help="Choices: API, SFTP, ManualFile, GlobalUpload, GlobalSFTP"),
|
|
139
|
+
output: str = typer.Option("table", "--output", "-o", help="Output format: table|json"),
|
|
140
|
+
limit: int = typer.Option(0, "--limit", help="Max results (0=all for paginated endpoints, API default for non-paginated)"),
|
|
141
|
+
offset: int = typer.Option(0, "--offset", help="Start offset"),
|
|
142
|
+
debug: bool = typer.Option(False, "--debug"),
|
|
143
|
+
):
|
|
144
|
+
"""Get Contact Lists within a Campaign."""
|
|
145
|
+
api = get_api(debug=debug)
|
|
146
|
+
cc_base_url = get_cc_base_url()
|
|
147
|
+
url = f"{cc_base_url}/v3/campaign-management/campaigns/{campaign_id}/contact-lists"
|
|
148
|
+
params = {}
|
|
149
|
+
if status is not None:
|
|
150
|
+
params["status"] = status
|
|
151
|
+
if source is not None:
|
|
152
|
+
params["source"] = source
|
|
153
|
+
if limit > 0:
|
|
154
|
+
params["max"] = limit
|
|
155
|
+
if offset > 0:
|
|
156
|
+
params["start"] = offset
|
|
157
|
+
result = None
|
|
158
|
+
try:
|
|
159
|
+
result = api.session.rest_get(url, params=params)
|
|
160
|
+
except WebexError as e:
|
|
161
|
+
handle_rest_error(e)
|
|
162
|
+
result = result or []
|
|
163
|
+
items = result.get("contactLists", result.get("data", result if isinstance(result, list) else [])) if isinstance(result, dict) else (result if isinstance(result, list) else [])
|
|
164
|
+
if output == "json":
|
|
165
|
+
print_json(items)
|
|
166
|
+
else:
|
|
167
|
+
print_table(items, columns=[("ID", "id"), ("Name", "name")], limit=limit)
|
|
168
|
+
|
|
169
|
+
|