Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changelog/44750.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_connect_routing_profile: Add `media_concurrencies.cross_channel_behavior` argument
```

```release-note:enhancement
data-source/aws_connect_routing_profile: Add `media_concurrencies.cross_channel_behavior` attribute
```
1 change: 1 addition & 0 deletions internal/service/connect/connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ func TestAccConnect_serial(t *testing.T) {
acctest.CtDisappears: testAccRoutingProfile_disappears,
"tags": testAccRoutingProfile_updateTags,
"concurrency": testAccRoutingProfile_updateConcurrency,
"crossChannelBehavior": testAccRoutingProfile_crossChannelBehavior,
"defaultOutboundQueue": testAccRoutingProfile_updateDefaultOutboundQueue,
"queues": testAccRoutingProfile_updateQueues,
"createQueueBatchAssociations": testAccRoutingProfile_createQueueConfigsBatchedAssociateDisassociate,
Expand Down
66 changes: 64 additions & 2 deletions internal/service/connect/routing_profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ func resourceRoutingProfile() *schema.Resource {
Required: true,
ValidateFunc: validation.IntBetween(1, 10),
},
"cross_channel_behavior": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"behavior_type": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: enum.Validate[awstypes.BehaviorType](),
},
},
},
},
},
},
},
Expand Down Expand Up @@ -201,7 +216,7 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met
d.Set("default_outbound_queue_id", routingProfile.DefaultOutboundQueueId)
d.Set(names.AttrDescription, routingProfile.Description)
d.Set(names.AttrInstanceID, instanceID)
if err := d.Set("media_concurrencies", flattenMediaConcurrencies(routingProfile.MediaConcurrencies)); err != nil {
if err := d.Set("media_concurrencies", flattenMediaConcurrencies(routingProfile.MediaConcurrencies, d.Get("media_concurrencies").(*schema.Set).List())); err != nil {
return sdkdiag.AppendErrorf(diags, "setting media_concurrencies: %s", err)
}
d.Set(names.AttrName, routingProfile.Name)
Expand Down Expand Up @@ -477,21 +492,68 @@ func expandMediaConcurrencies(tfList []any) []awstypes.MediaConcurrency {
Channel: awstypes.Channel(tfMap["channel"].(string)),
Concurrency: aws.Int32(int32(tfMap["concurrency"].(int))),
}

if v, ok := tfMap["cross_channel_behavior"].([]any); ok && len(v) > 0 {
apiObject.CrossChannelBehavior = expandCrossChannelBehavior(v)
}

apiObjects = append(apiObjects, apiObject)
}

return apiObjects
}

func flattenMediaConcurrencies(apiObjects []awstypes.MediaConcurrency) []any {
func expandCrossChannelBehavior(tfList []any) *awstypes.CrossChannelBehavior {
if len(tfList) == 0 {
return nil
}

tfMap := tfList[0].(map[string]any)

return &awstypes.CrossChannelBehavior{
BehaviorType: awstypes.BehaviorType(tfMap["behavior_type"].(string)),
}
}

func flattenCrossChannelBehavior(apiObject *awstypes.CrossChannelBehavior) []map[string]any {
if apiObject == nil {
return nil
}

return []map[string]any{
{
"behavior_type": string(apiObject.BehaviorType),
},
}
}

func flattenMediaConcurrencies(apiObjects []awstypes.MediaConcurrency, configList ...[]any) []any {
tfList := []any{}

configuredBehaviors := make(map[string]bool)
if len(configList) > 0 && configList[0] != nil {
for _, configRaw := range configList[0] {
configMap := configRaw.(map[string]any)
channel := configMap["channel"].(string)
if crossChannelBehaviorList, ok := configMap["cross_channel_behavior"].([]any); ok && len(crossChannelBehaviorList) > 0 {
configuredBehaviors[channel] = true
}
}
}

for _, apiObject := range apiObjects {
tfMap := map[string]any{
"channel": apiObject.Channel,
"concurrency": aws.ToInt32(apiObject.Concurrency),
}

channel := string(apiObject.Channel)
if apiObject.CrossChannelBehavior != nil {
if len(configList) == 0 || configuredBehaviors[channel] {
tfMap["cross_channel_behavior"] = flattenCrossChannelBehavior(apiObject.CrossChannelBehavior)
}
}

tfList = append(tfList, tfMap)
}

Expand Down
12 changes: 12 additions & 0 deletions internal/service/connect/routing_profile_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ func dataSourceRoutingProfile() *schema.Resource {
Type: schema.TypeInt,
Computed: true,
},
"cross_channel_behavior": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"behavior_type": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
},
},
},
Expand Down
169 changes: 169 additions & 0 deletions internal/service/connect/routing_profile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,80 @@ func testAccRoutingProfile_updateQueues(t *testing.T) {
})
}

func testAccRoutingProfile_crossChannelBehavior(t *testing.T) {
ctx := acctest.Context(t)
var v awstypes.RoutingProfile
rName := sdkacctest.RandomWithPrefix("resource-test-terraform")
rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform")
rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform")
resourceName := "aws_connect_routing_profile.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.ConnectServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckRoutingProfileDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccRoutingProfileConfig_crossChannelBehaviorDefault(rName, rName2, rName3),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoutingProfileExists(ctx, resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "2"),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{
"channel": string(awstypes.ChannelVoice),
"concurrency": "1",
"cross_channel_behavior.#": "0",
}),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{
"channel": string(awstypes.ChannelChat),
"concurrency": "2",
"cross_channel_behavior.#": "0",
}),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccRoutingProfileConfig_crossChannelBehaviorCurrentChannelOnly(rName, rName2, rName3),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoutingProfileExists(ctx, resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "2"),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{
"channel": string(awstypes.ChannelVoice),
"concurrency": "1",
"cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteCurrentChannelOnly),
}),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{
"channel": string(awstypes.ChannelChat),
"concurrency": "3",
"cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteCurrentChannelOnly),
}),
),
},
{
Config: testAccRoutingProfileConfig_crossChannelBehaviorMixed(rName, rName2, rName3),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoutingProfileExists(ctx, resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "2"),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{
"channel": string(awstypes.ChannelVoice),
"concurrency": "1",
"cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteAnyChannel),
}),
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "media_concurrencies.*", map[string]string{
"channel": string(awstypes.ChannelChat),
"concurrency": "3",
"cross_channel_behavior.0.behavior_type": string(awstypes.BehaviorTypeRouteCurrentChannelOnly),
}),
),
},
},
})
}

func testAccRoutingProfile_updateTags(t *testing.T) {
ctx := acctest.Context(t)
var v awstypes.RoutingProfile
Expand Down Expand Up @@ -997,3 +1071,98 @@ resource "aws_connect_routing_profile" "test" {
}
`, rName3))
}

func testAccRoutingProfileConfig_crossChannelBehaviorDefault(rName, rName2, rName3 string) string {
return acctest.ConfigCompose(
testAccRoutingProfileConfig_base(rName, rName2),
fmt.Sprintf(`
resource "aws_connect_routing_profile" "test" {
instance_id = aws_connect_instance.test.id
name = %[1]q
default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id
description = "Test cross-channel behavior - default"

media_concurrencies {
channel = "VOICE"
concurrency = 1
# behaviour uses AWS server-side default
}

media_concurrencies {
channel = "CHAT"
concurrency = 2
# behaviour uses AWS server-side default
}

tags = {
"Name" = "Test Routing Profile Cross-Channel Behavior",
}
}
`, rName3))
}

func testAccRoutingProfileConfig_crossChannelBehaviorCurrentChannelOnly(rName, rName2, rName3 string) string {
return acctest.ConfigCompose(
testAccRoutingProfileConfig_base(rName, rName2),
fmt.Sprintf(`
resource "aws_connect_routing_profile" "test" {
instance_id = aws_connect_instance.test.id
name = %[1]q
default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id
description = "Test cross-channel behavior - current channel only"

media_concurrencies {
channel = "VOICE"
concurrency = 1
cross_channel_behavior {
behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY"
}
}

media_concurrencies {
channel = "CHAT"
concurrency = 3
cross_channel_behavior {
behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY"
}
}

tags = {
"Name" = "Test Routing Profile Cross-Channel Behavior",
}
}
`, rName3))
}

func testAccRoutingProfileConfig_crossChannelBehaviorMixed(rName, rName2, rName3 string) string {
return acctest.ConfigCompose(
testAccRoutingProfileConfig_base(rName, rName2),
fmt.Sprintf(`
resource "aws_connect_routing_profile" "test" {
instance_id = aws_connect_instance.test.id
name = %[1]q
default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id
description = "Test cross-channel behavior - mixed"

media_concurrencies {
channel = "VOICE"
concurrency = 1
cross_channel_behavior {
behavior_type = "ROUTE_ANY_CHANNEL"
}
}

media_concurrencies {
channel = "CHAT"
concurrency = 3
cross_channel_behavior {
behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY"
}
}

tags = {
"Name" = "Test Routing Profile Cross-Channel Behavior",
}
}
`, rName3))
}
5 changes: 5 additions & 0 deletions website/docs/d/connect_routing_profile.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ A `media_concurrencies` block supports the following attributes:

* `channel` - Channels that agents can handle in the Contact Control Panel (CCP). Valid values are `VOICE`, `CHAT`, `TASK`.
* `concurrency` - Number of contacts an agent can have on a channel simultaneously. Valid Range for `VOICE`: Minimum value of 1. Maximum value of 1. Valid Range for `CHAT`: Minimum value of 1. Maximum value of 10. Valid Range for `TASK`: Minimum value of 1. Maximum value of 10.
* `cross_channel_behavior` - Configuration block for cross-channel behavior. Documented below.

A `cross_channel_behavior` block supports the following attributes:

* `behavior_type` - Cross-channel behavior for routing contacts across multiple channels. Valid values are `ROUTE_CURRENT_CHANNEL_ONLY`, `ROUTE_ANY_CHANNEL`.

A `queue_configs` block supports the following attributes:

Expand Down
16 changes: 16 additions & 0 deletions website/docs/r/connect_routing_profile.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ resource "aws_connect_routing_profile" "example" {
media_concurrencies {
channel = "VOICE"
concurrency = 1
cross_channel_behavior {
behavior_type = "ROUTE_ANY_CHANNEL"
}
}

media_concurrencies {
channel = "CHAT"
concurrency = 3
cross_channel_behavior {
behavior_type = "ROUTE_CURRENT_CHANNEL_ONLY"
}
}

queue_configs {
Expand Down Expand Up @@ -56,6 +67,11 @@ A `media_concurrencies` block supports the following arguments:

* `channel` - (Required) Specifies the channels that agents can handle in the Contact Control Panel (CCP). Valid values are `VOICE`, `CHAT`, `TASK`.
* `concurrency` - (Required) Specifies the number of contacts an agent can have on a channel simultaneously. Valid Range for `VOICE`: Minimum value of 1. Maximum value of 1. Valid Range for `CHAT`: Minimum value of 1. Maximum value of 10. Valid Range for `TASK`: Minimum value of 1. Maximum value of 10.
* `cross_channel_behavior` - (Optional) Configuration block for cross-channel behavior. If not specified, AWS will use the service default behavior. Documented below.

A `cross_channel_behavior` block supports the following arguments:

* `behavior_type` - (Required) Specifies the cross-channel behavior for routing contacts across multiple channels. `ROUTE_ANY_CHANNEL` allows agents to receive contacts from any channel regardless of what they are currently handling. `ROUTE_CURRENT_CHANNEL_ONLY` restricts agents to receive contacts only from the channel they are currently handling. Valid values are `ROUTE_CURRENT_CHANNEL_ONLY`, `ROUTE_ANY_CHANNEL`.

A `queue_configs` block supports the following arguments:

Expand Down
Loading