diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/README.md b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/README.md
index e583f433..f9c7eb2f 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/README.md
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/README.md
@@ -4,10 +4,17 @@ This scenario allows employees to add new dependents to their Workday profile fo
## Overview
-The `AddDependents` topic allows employees to:
+The `EmployeeAddDependents` topic allows employees to:
1. **View** their existing dependents
2. **Add** a new dependent (spouse, child, domestic partner, etc.)
+## Features
+
+- **View Existing Dependents**: Displays a list of the employee's current dependents with their relationship and date of birth
+- **Add New Dependent**: Allows employees to add a new dependent with full details
+- **Relationship Types**: Dynamic dropdown populated from Workday reference data
+- **Confirmation Flow**: Shows summary of dependent details before submission
+
## Flow
```
@@ -73,9 +80,9 @@ The `AddDependents` topic allows employees to:
| File | Purpose |
|------|---------|
-| `AddDependents_Topic.yaml` | Main topic definition with full flow |
-| `msdyn_GetDependents_Template.xml` | XML template for fetching existing dependents |
-| `msdyn_AddDependent_Template.xml` | XML template for adding a new dependent |
+| `topic.yaml` | Main topic definition with full flow |
+| `msdyn_HRWorkdayHCMEmployeeGetDependents.xml` | XML template for fetching existing dependents |
+| `msdyn_HRWorkdayHCMEmployeeAddDependent.xml` | XML template for adding a new dependent |
## API Scenarios Used
@@ -159,10 +166,65 @@ This ensures that only `Related_Person` nodes containing a `Dependent` child ele
- "Add my spouse to my benefits"
- "Register a new dependent"
- "I need to add a family member"
+- "Show my dependents"
+- "Who are my dependents?"
## Dependencies
- `msdyn_copilotforemployeeselfservicehr.topic.GetReferenceData` - For fetching relationship types
- `msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution` - For API execution
- `Global.RelatedPersonRelationshipLookupTable` - Relationship types lookup
-- `Global.ESS_UserContext_Employee_Id` - Current user's employee ID
\ No newline at end of file
+- `Global.ESS_UserContext_Employee_Id` - Current user's employee ID
+
+## Trigger Phrases
+
+- "Add a dependent"
+- "I want to add my child as a dependent"
+- "Add my spouse to my benefits"
+- "Register a new dependent"
+- "I need to add a family member"
+- "Show my dependents"
+- "Who are my dependents?"
+
+## Example Interaction
+
+**User**: "I want to add my child as a dependent"
+
+**Agent**: Shows existing dependents (if any) and displays the Add Dependent form
+
+**User**: Fills in child's details (name, DOB, gender, relationship)
+
+**Agent**: Shows confirmation card with summary of dependent details
+
+**User**: Confirms "Yes, add this dependent"
+
+**Agent**: "✅ Your dependent has been successfully added!"
+
+## Setup Instructions
+
+1. **Import the Topic**: Import `topic.yaml` into your Copilot Studio agent
+2. **Add XML Templates**: Upload both XML templates to your Workday connector configuration
+3. **Configure Connection**: Ensure your Workday connector connection reference is set in the topic
+4. **Set Global Variable**: Ensure `Global.ESS_UserContext_Employee_Id` is populated from user authentication
+
+## Notes
+
+- Relationship types are dynamically loaded from Workday reference data
+- The topic validates that all required fields are completed before submission
+- Gender options are hardcoded as Male, Female, and Not_Declared to match Workday values
+- Country codes use ISO 3166-1 Alpha-3 format (e.g., USA, CAN, GBR)
+
+## Error Handling
+
+| Scenario | Behavior |
+|----------|----------|
+| Failed to fetch dependents | Error message displayed, dialog ends |
+| Failed to add dependent | Error message with option to retry |
+| User cancels | Dialog ends gracefully |
+| Missing required fields | Form validation prevents submission |
+
+## Version History
+
+| Version | Date | Changes |
+|---------|------|---------|
+| 1.0 | December 2025 | Initial release with Add Dependent functionality |
\ No newline at end of file
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/msdyn_AddDependent_Template.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/msdyn_AddDependent_Template.xml
new file mode 100644
index 00000000..02744f36
--- /dev/null
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/msdyn_AddDependent_Template.xml
@@ -0,0 +1,65 @@
+
+
+
+
+ User
+
+ Template_AddDependentRequest
+ Benefits_Administration
+ v45.1
+
+
+
+ //*[local-name()='Dependent_Reference']/*[local-name()='ID' and @*[local-name()='type']='WID']/text()
+ DependentWID
+
+
+ //*[local-name()='Dependent_Reference']/*[local-name()='ID' and @*[local-name()='type']='Dependent_ID']/text()
+ DependentID
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+
+ Dependent added via Copilot
+
+ {Employee_ID}
+
+
+
+
+
+ {Employee_ID}
+
+
+ {Relationship_Type}
+
+ true
+
+
+
+
+ {Country_Code}
+
+ {First_Name}
+ {Last_Name}
+
+
+ {Date_Of_Birth}
+
+ {Gender}
+
+
+
+
+
+
+
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/msdyn_GetDependents_Template.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/msdyn_GetDependents_Template.xml
new file mode 100644
index 00000000..7a87290b
--- /dev/null
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/msdyn_GetDependents_Template.xml
@@ -0,0 +1,104 @@
+
+
+
+
+ User
+
+ Template_GetDependentsRequest
+ Human_Resources
+ v42.0
+
+
+
+
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Dependent']/*[local-name()='Dependent_Reference']/*[local-name()='ID' and @*[local-name()='type']='Dependent_ID']/text()
+ DependentID
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Dependent']/*[local-name()='Dependent_Reference']/*[local-name()='ID' and @*[local-name()='type']='WID']/text()
+ DependentWID
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Person_Reference']/*[local-name()='ID' and @*[local-name()='type']='WID']/text()
+ PersonWID
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Personal_Data']/*[local-name()='Name_Data']/*[local-name()='Legal_Name_Data']/*[local-name()='Name_Detail_Data']/@*[local-name()='Formatted_Name']
+ FullName
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Personal_Data']/*[local-name()='Name_Data']/*[local-name()='Legal_Name_Data']/*[local-name()='Name_Detail_Data']/*[local-name()='First_Name']/text()
+ FirstName
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Personal_Data']/*[local-name()='Name_Data']/*[local-name()='Legal_Name_Data']/*[local-name()='Name_Detail_Data']/*[local-name()='Last_Name']/text()
+ LastName
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Personal_Data']/*[local-name()='Personal_Information_Data']/*[local-name()='Birth_Date']/text()
+ DateOfBirth
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Personal_Data']/*[local-name()='Personal_Information_Data']//*[local-name()='Gender_Reference']/*[local-name()='ID' and @*[local-name()='type']='Gender_Code']/text()
+ Gender
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Related_Person_Relationship_Reference']/*[local-name()='ID' and @*[local-name()='type']='Related_Person_Relationship_ID']/text()
+ RelationshipTypeID
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Dependent']/*[local-name()='Dependent_Data']/*[local-name()='Full-time_Student']/text()
+ IsFullTimeStudent
+
+
+
+ //*[local-name()='Related_Person_Data']/*[local-name()='Related_Person'][*[local-name()='Dependent']]/*[local-name()='Dependent']/*[local-name()='Dependent_Data']/*[local-name()='Disabled']/text()
+ IsDisabled
+
+
+
+
+
+
+
+
+
+
+ {Employee_ID}
+
+
+
+ {As_Of_Effective_Date}
+
+
+ true
+ false
+ false
+ false
+ false
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ false
+ false
+
+
+
+
+
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/topic.yaml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/topic.yaml
index ab72de4f..41e950a0 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/topic.yaml
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeAddDependents/topic.yaml
@@ -23,6 +23,12 @@ beginDialog:
intent: {}
actions:
+ # Set Workday icon URL
+ - kind: SetVariable
+ id: set_workday_icon_url
+ variable: Topic.WorkdayIconUrl
+ value: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAExUlEQVR4nOVbSUwUQRT9XSJxQVExLoQZLwJGGZfEJcY5KJx0Er2piF7d4hkTTby5njxoRE9eHM5oxqOY2O5jXFAjYFzAgBrEDKIxGpf8xta2+ld1z3T1TPfMSwiZ7vrd9V69/391D2jgEZWLd/6CAiPz6JyWa6wWVtKqxNCKhXiuQmjFRjxbIVgxk3czf+YlOCyQ8WC5BIURIj4sm8FhB8WLuRlUTOD5MdnJYoWVZ1nebjruGzRMHIbYhGFomPDB+Iw/iMyPcuj6WgWPv86A66NzjM/5gub36q+peAvN03phw9S+v4SdcP3zHGj/WAvtH+eD33sEzS8BouWjcKrmGqyZ/Dbna/R9q4AT75f5JkTGFEA1+d0zn8DhuXeUXQ8FODi4ypfUYCovhhY/HbmmlDyiefpzuDq/w3CVamgqHYCTjE0clo4Z+VkO+uhcw96Zn2MrioURyWFxlAFjNr1cb/xWBU0V+SPVt2FX1VPhebOoYYETAUVonfUA4hWDEBlPrzaSX/t8k7J00FQIsH/2fWPiFLC1HRhYJSUuEqJ5ei95/vJIFHa8boJA1IDon8mKVn3ji/VZkTdXed+bOBx/t4w8jy0V60IgBGiddV9IHkl4seqJ90uFIuB93e4rfBMgWj5KrkT/9wo4OLgSVABFaBtaRN57qwIXMD9Wf/urJqU9G0WgrpeY+rqwAjQQLe/yyDyj8KkEkm/7YHcB7jK97g3KvAS3D9fCY04EXC0/cHZoIVSyfw9QpjBe9wRaqTwC52UrHEYwKHEwKHEwKHEwKHGUeQnetnE1RKur/juWvHgT+gbEj7Wx+hpIrLO3SozBWBn2tDRC5ZRJWcX4KsDR1s3/TQgRrZ4Jew+dF8ZcOLnXJpqJru5+6Op+Q55D0Y62brEd19O90DcwBAVJgS5isrEFNcLx8eV1QvJj5+ulsTwyn754Iu9dgGf9tmMygmh/GRKN4l1kbEHEfn+BW/ImgJ7usR3DlMA0oJBopB9trQLxKWU9R6VM4ARAxJfXAg8kRtmYH0OlUKw+Qgqj3+2GggqQEeQgZVeKfOqK/U0S1SHERbPAKYDQ7/a4IptoXGI7dqztkiGikwDU9bAFytpt/gRI97iyLF/hcfK4grwLcLX5WMpRlPCBEQBhzWUkxdvYJEDF4wbLyQF62nv+KxEAV5K3MSJWF5Hnf+fY67RU50N7bL08ViZ8QZ4FUkQxs06c6u+4g0OgeHwxs9YLqv2pyn9lAlCrEV9RJ1xFHG91Dd/OjJb5J57aO6jKf3UOIGxskkDyfFHjHZPqFDuIcoCZPoERIEPY2KwDVFvjCxjvCLNrUOKNjae/Mivo+wCd2JVh7sdX0O3PKY2QPF077GIFQoCUwMa8hUX5Swm4p6XJVcENhgPS7lZG1L+TF2+5vI+a/u/LK7Fkh/PbGVH/FtURN+njBczLPxu4SQOevKx/Oz3dOV2/4A7QHdLAK8Fkxw0I/FvhpCQN9Hs9OQvoh/3/CpCPNEACbnZwIpLHzlyC0PyhZIx4tYXE3PZvfuvspkB6FgBRSt8Um65nUOJg1g8qa0GQYeXJZCeLETw/5mZQsYDixbIZHGaI+LBcgsIGGQ/mJTgMcJq/ls3FSvZ/h4FDkIXI1rG/Adz0VZDmVyKYAAAAAElFTkSuQmCC
+
# Step 1: Fetch reference data for relationship types
- kind: ConditionGroup
id: checkRelationshipTypes
@@ -184,78 +190,126 @@ beginDialog:
={
type: "AdaptiveCard",
'$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
- version: "1.3",
+ version: "1.5",
body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
{
type: "TextBlock",
- text: "Add New Dependent",
+ text: "Add a new dependent",
weight: "Bolder",
- size: "Large",
- color: "Default"
+ size: "Medium",
+ wrap: true,
+ spacing: "Medium"
},
{
type: "TextBlock",
- text: "Please enter the dependent's information:",
- wrap: true
+ text: "Fields marked with * are required.",
+ wrap: true,
+ size: "Small",
+ spacing: "Small"
},
{
type: "Input.Text",
id: "firstName",
- label: "First Name",
+ label: "First name",
placeholder: "Enter first name",
- isRequired: true
+ isRequired: true,
+ errorMessage: "First name is required."
},
{
type: "Input.Text",
id: "lastName",
- label: "Last Name",
+ label: "Last name",
placeholder: "Enter last name",
- isRequired: true
+ isRequired: true,
+ errorMessage: "Last name is required."
},
{
type: "Input.Date",
id: "dateOfBirth",
- label: "Date of Birth",
- isRequired: true
+ label: "Date of birth",
+ isRequired: true,
+ errorMessage: "Date of birth is required."
},
{
type: "Input.ChoiceSet",
id: "gender",
label: "Gender",
+ style: "compact",
isRequired: true,
+ errorMessage: "Please select a gender.",
+ placeholder: "Select gender",
choices: [
{ title: "Male", value: "Male" },
{ title: "Female", value: "Female" },
- { title: "Not Declared", value: "Not_Declared" }
+ { title: "Not declared", value: "Not_Declared" }
]
},
{
type: "Input.ChoiceSet",
id: "relationshipType",
- label: "Relationship",
+ label: "Relationship to employee",
+ style: "compact",
isRequired: true,
+ errorMessage: "Please select a relationship.",
+ placeholder: "Select relationship",
choices: ForAll(Global.RelatedPersonRelationshipLookupTable, { title: ThisRecord.Referenced_Object_Descriptor, value: ThisRecord.ID })
},
{
type: "Input.ChoiceSet",
id: "country",
label: "Country",
+ style: "compact",
isRequired: true,
+ errorMessage: "Please select a country.",
value: "USA",
choices: [
{ title: "United States", value: "USA" },
{ title: "Canada", value: "CAN" },
{ title: "United Kingdom", value: "GBR" },
+ { title: "India", value: "IND" },
{ title: "Australia", value: "AUS" },
{ title: "Germany", value: "DEU" },
- { title: "France", value: "FRA" },
- { title: "India", value: "IND" }
+ { title: "France", value: "FRA" }
]
}
],
actions: [
- { type: "Action.Submit", title: "Add Dependent" },
- { type: "Action.Submit", title: "Cancel", associatedInputs: "none" }
+ { type: "Action.Submit", title: "Submit", id: "Submit", data: { actionSubmitId: "Submit" } },
+ { type: "Action.Submit", title: "Cancel", id: "Cancel", data: { actionSubmitId: "Cancel" }, associatedInputs: "none" }
]
}
output:
@@ -295,11 +349,11 @@ beginDialog:
id: validateFields
conditions:
- id: missingFieldsCondition
- condition: =IsBlank(Topic.firstName) || IsBlank(Topic.lastName) || IsBlank(Topic.dateOfBirth) || IsBlank(Topic.gender) || IsBlank(Topic.relationshipType)
+ condition: =IsBlank(Topic.firstName) || IsBlank(Topic.lastName) || IsBlank(Topic.dateOfBirth) || IsBlank(Topic.gender) || IsBlank(Topic.relationshipType) || IsBlank(Topic.country)
actions:
- kind: SendActivity
id: sendValidationError
- activity: Please fill in all required fields (First Name, Last Name, Date of Birth, Gender, and Relationship).
+ activity: Please fill in all required fields (first name, last name, date of birth, gender, relationship, and country).
- kind: EndDialog
id: endOnValidationError
@@ -332,22 +386,95 @@ beginDialog:
- id: addSuccessCondition
condition: =Topic.addIsSuccess = true
actions:
+ - kind: SendActivity
+ id: sendSuccessIntroMessage
+ activity: Great! You've added a new dependent.
+
+ - kind: SetVariable
+ id: setOtherDependentsList
+ variable: Topic.otherDependentsList
+ value: =If(CountRows(Topic.dependentsTable) > 0, Concat(Topic.dependentsTable, FullName, ", "), "None")
+
- kind: SendActivity
id: sendSuccessMessage
- activity: |-
- ✅ **Dependent added successfully!**
-
- **{Topic.firstName} {Topic.lastName}** has been added as your **{LookUp(Global.RelatedPersonRelationshipLookupTable, ID = Topic.relationshipType).Referenced_Object_Descriptor}**.
-
- Please note that depending on your company's policies, this change may require approval before it takes effect.
+ activity:
+ attachments:
+ - kind: AdaptiveCardTemplate
+ cardContent: |-
+ ={
+ type: "AdaptiveCard",
+ '$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
+ version: "1.5",
+ body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
+ {
+ type: "TextBlock",
+ text: "✅ Your new dependent was added",
+ weight: "Bolder",
+ size: "Medium",
+ wrap: true,
+ spacing: "Medium"
+ },
+ {
+ type: "FactSet",
+ spacing: "Medium",
+ facts: [
+ { title: "Name", value: Topic.firstName & " " & Topic.lastName },
+ { title: "Date of birth", value: Topic.dateOfBirth },
+ { title: "Gender", value: Topic.gender },
+ { title: "Relationship to employee", value: LookUp(Global.RelatedPersonRelationshipLookupTable, ID = Topic.relationshipType).Referenced_Object_Descriptor },
+ { title: "Other dependents", value: Topic.otherDependentsList }
+ ]
+ }
+ ]
+ }
+
+ - kind: CancelAllDialogs
+ id: endOnSuccess
elseActions:
- kind: SendActivity
id: sendAddErrorMessage
activity: |-
- ❌ There was an error adding the dependent. Please try again later or contact HR support.
+ There was an error adding the dependent. Please try again later or contact HR support.
- Error: {Topic.addErrorResponse}
+ **Error details:** {Topic.addErrorResponse}
+
+ - kind: CancelAllDialogs
+ id: endOnError2
inputType: {}
outputType:
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/README.md b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/README.md
index bb855fc3..724a600f 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/README.md
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/README.md
@@ -1,15 +1,23 @@
# Workday Update Residential Address
## Overview
-This scenario enables employees to update their home/residential address in Workday through the Copilot agent. It retrieves the employee's current home addresses, allows them to select which one to update, and submits the changes via the Workday Change Home Contact Information API.
+This scenario enables employees to manage their home/residential address in Workday through the Copilot agent. It retrieves the employee's current home addresses, allows them to select which one to update, add a new address, or modify an existing one, and submits the changes via the Workday Change Home Contact Information API.
+
+## Features
+
+- **View Current Addresses**: Displays the employee's existing home addresses with primary address marked
+- **Update Existing Address**: Modify any field of an existing home address
+- **Add New Address**: Add a new home address when no addresses exist or when user wants to add another
+- **Primary Address Management**: Set or change which address is the primary home address
## Files
| File | Description |
|------|-------------|
-| `UpdateResidentialAddress_Topic.yaml` | Copilot Studio topic definition with the complete workflow |
+| `topic.yaml` | Copilot Studio topic definition with the complete workflow |
| `msdyn_GetResidentialAddress_Template.xml` | XML template to retrieve current home addresses |
-| `msdyn_UpdateResidentialAddress_Template.xml` | XML template to update the home address |
+| `msdyn_UpdateResidentialAddress_Template.xml` | XML template to update an existing home address |
+| `msdyn_AddResidentialAddress_Template.xml` | XML template to add a new home address |
## Prerequisites
@@ -21,15 +29,77 @@ This scenario enables employees to update their home/residential address in Work
- **Version**: v42.0
- **Operations**:
- `Get_Workers` - To retrieve current address information
- - `Change_Home_Contact_Information` - To update address
+ - `Change_Home_Contact_Information` - To add or update address
## Workflow
+```
+┌─────────────────────────────────────────────────────────────┐
+│ User Triggers Topic │
+│ "Update my home address" / "Change my address" │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Fetch Current Home Addresses │
+│ (Get_Workers API) │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ▼
+ ┌───────────────┴───────────────┐
+ │ Has Existing Addresses? │
+ └───────────────┬───────────────┘
+ │ │
+ Yes No
+ │ │
+ ▼ ▼
+ ┌───────────────────────┐ ┌─────────────────┐
+ │ Show Selection Card │ │ Show Add Form │
+ │ • Existing addresses │ │ (empty form) │
+ │ ➕ Add New Address │ │ │
+ └───────────────────────┘ └─────────────────┘
+ │ │
+ ▼ │
+ ┌───────────────────────┐ │
+ │ User Selects │ │
+ │ Address or Add New │ │
+ └───────────────────────┘ │
+ │ │
+ ┌───────┴───────┐ │
+ │ │ │
+ ▼ ▼ ▼
+┌───────────┐ ┌───────────────────────────┐
+│ Update │ │ Add New Address Form │
+│ Form │ │ │
+│(pre-fill) │ │ │
+└───────────┘ └───────────────────────────┘
+ │ │
+ └─────────┬─────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Show Confirmation Card │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Submit to Workday │
+│ (Change_Home_Contact_Information API) │
+└─────────────────────────────────────────────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────────────────────────────┐
+│ Display Success/Error Message │
+└─────────────────────────────────────────────────────────────┘
+```
+
+## Workflow Steps
+
1. **Retrieve Current Addresses**: Calls Get_Workers API with `Include_Personal_Information` to get existing home addresses
-2. **Select Address**: If multiple addresses exist, user selects which one to update
-3. **Collect New Address**: Displays an Adaptive Card form pre-filled with current values
+2. **Select Address**: If addresses exist, user selects which one to update or chooses to add new
+3. **Collect Address Data**: Displays an Adaptive Card form (pre-filled for updates, empty for new)
4. **Confirm Changes**: Shows summary of changes and asks for confirmation
-5. **Submit Update**: Calls Change_Home_Contact_Information API to update the address
+5. **Submit**: Calls Change_Home_Contact_Information API to add or update the address
6. **Display Result**: Shows success or error message
## Address Fields
@@ -73,6 +143,7 @@ Pre-configured for:
- "Change my address"
- "Update my street address"
- "I moved to a new address"
+- "Add a new home address"
## XML Template Parameters
@@ -96,6 +167,19 @@ Pre-configured for:
| `{Postal_Code}` | ZIP/Postal code |
| `{Is_Primary}` | true/false for primary address |
+### Add Address Template (`msdyn_HRWorkdayHCMEmployeeAddResidentialAddress`)
+| Parameter | Description |
+|-----------|-------------|
+| `{Employee_ID}` | Employee's Workday ID |
+| `{Event_Effective_Date}` | Effective date of the change |
+| `{Country_Code}` | ISO 3166-1 Alpha-3 country code |
+| `{State_Province_Code}` | Country Region ID (e.g., USA-CA) |
+| `{Address_Line_1}` | Street address line 1 |
+| `{Address_Line_2}` | Street address line 2 (optional) |
+| `{City}` | Municipality name |
+| `{Postal_Code}` | ZIP/Postal code |
+| `{Is_Primary}` | true/false for primary address |
+
## Response Extraction
### Get Address Response
@@ -110,12 +194,14 @@ Pre-configured for:
## Setup Instructions
-1. **Import the Topic**: Import `UpdateResidentialAddress_Topic.yaml` into your Copilot Studio agent
-2. **Add XML Templates**: Upload both XML templates to your Workday connector configuration
+1. **Import the Topic**: Import `topic.yaml` into your Copilot Studio agent
+2. **Add XML Templates**: Upload all three XML templates to your Workday connector configuration
3. **Configure Connection**: Ensure your Workday connector connection reference is set in the topic
4. **Set Global Variable**: Ensure `Global.ESS_UserContext_Employee_Id` is populated from user authentication
-## Example Interaction
+## Example Interactions
+
+### Updating an Existing Address
**User**: "I need to update my home address"
@@ -133,8 +219,37 @@ Pre-configured for:
**Agent**: "✅ Your home address has been successfully updated!"
+### Adding a New Address
+
+**User**: "Add a new home address"
+
+**Agent**: "I don't see any existing home addresses on file. Let me help you add one."
+
+**Agent**: Displays empty Adaptive Card form
+
+**User**: Fills in address details and clicks "Add Address"
+
+**Agent**: Shows confirmation with new address details
+
+**User**: Confirms
+
+**Agent**: "✅ Your new home address has been successfully added!"
+
## Notes
- The `Replace_All="false"` setting ensures only the selected address is updated without affecting other addresses
- Business process parameters include `Auto_Complete=false` and `Run_Now=true` for proper workflow handling
- Address validation is handled by Workday - ensure state/province codes match the country selected
+- When adding a new address, no Address_ID is required as Workday generates one automatically
+
+## Dependencies
+
+- `msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution` - For API execution
+- `Global.ESS_UserContext_Employee_Id` - Current user's employee ID
+
+## Version History
+
+| Version | Date | Changes |
+|---------|------|---------|
+| 1.0 | December 2025 | Initial release with Update functionality |
+| 1.1 | February 2026 | Added Add New Address functionality |
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/msdyn_AddResidentialAddress_Template.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/msdyn_AddResidentialAddress_Template.xml
new file mode 100644
index 00000000..74699815
--- /dev/null
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/msdyn_AddResidentialAddress_Template.xml
@@ -0,0 +1,69 @@
+
+
+
+
+ User
+
+ Template_AddResidentialAddressRequest
+ Human_Resources
+ v42.0
+
+
+
+ //*[local-name()='Event_Reference']/*[local-name()='ID' and @*[local-name()='type']='WID']/text()
+ EventWID
+
+
+
+
+
+
+
+
+
+ false
+ true
+ true
+
+ New address added via Copilot
+
+ {Employee_ID}
+
+
+
+
+
+ {Employee_ID}
+
+ {Event_Effective_Date}
+
+
+
+
+
+ {Country_Code}
+
+
+ {State_Province_Code}
+
+ {Address_Line_1}
+ {Address_Line_2}
+ {Postal_Code}
+ {City}
+
+
+
+
+ HOME
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/topic.yaml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/topic.yaml
index 3980645f..8ecda47e 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/topic.yaml
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/EmployeeUpdateResidentialAddress/topic.yaml
@@ -203,11 +203,17 @@ beginDialog:
=ForAll(
Topic.homeAddresses,
{
- title: If(ThisRecord.IsPrimary, "⭐ ", "") & ThisRecord.FormattedAddress,
+ title: ThisRecord.AddressLine1 & ", " & ThisRecord.City & ", " & ThisRecord.StateProvinceCode & " " & ThisRecord.PostalCode & " (" & If(ThisRecord.IsPrimary, "Primary", "Home") & ")",
value: ThisRecord.AddressID
}
)
+ # Set Workday icon URL
+ - kind: SetVariable
+ id: set_workday_icon_url
+ variable: Topic.WorkdayIconUrl
+ value: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAExUlEQVR4nOVbSUwUQRT9XSJxQVExLoQZLwJGGZfEJcY5KJx0Er2piF7d4hkTTby5njxoRE9eHM5oxqOY2O5jXFAjYFzAgBrEDKIxGpf8xta2+ld1z3T1TPfMSwiZ7vrd9V69/391D2jgEZWLd/6CAiPz6JyWa6wWVtKqxNCKhXiuQmjFRjxbIVgxk3czf+YlOCyQ8WC5BIURIj4sm8FhB8WLuRlUTOD5MdnJYoWVZ1nebjruGzRMHIbYhGFomPDB+Iw/iMyPcuj6WgWPv86A66NzjM/5gub36q+peAvN03phw9S+v4SdcP3zHGj/WAvtH+eD33sEzS8BouWjcKrmGqyZ/Dbna/R9q4AT75f5JkTGFEA1+d0zn8DhuXeUXQ8FODi4ypfUYCovhhY/HbmmlDyiefpzuDq/w3CVamgqHYCTjE0clo4Z+VkO+uhcw96Zn2MrioURyWFxlAFjNr1cb/xWBU0V+SPVt2FX1VPhebOoYYETAUVonfUA4hWDEBlPrzaSX/t8k7J00FQIsH/2fWPiFLC1HRhYJSUuEqJ5ei95/vJIFHa8boJA1IDon8mKVn3ji/VZkTdXed+bOBx/t4w8jy0V60IgBGiddV9IHkl4seqJ90uFIuB93e4rfBMgWj5KrkT/9wo4OLgSVABFaBtaRN57qwIXMD9Wf/urJqU9G0WgrpeY+rqwAjQQLe/yyDyj8KkEkm/7YHcB7jK97g3KvAS3D9fCY04EXC0/cHZoIVSyfw9QpjBe9wRaqTwC52UrHEYwKHEwKHEwKHEwKHGUeQnetnE1RKur/juWvHgT+gbEj7Wx+hpIrLO3SozBWBn2tDRC5ZRJWcX4KsDR1s3/TQgRrZ4Jew+dF8ZcOLnXJpqJru5+6Op+Q55D0Y62brEd19O90DcwBAVJgS5isrEFNcLx8eV1QvJj5+ulsTwyn754Iu9dgGf9tmMygmh/GRKN4l1kbEHEfn+BW/ImgJ7usR3DlMA0oJBopB9trQLxKWU9R6VM4ARAxJfXAg8kRtmYH0OlUKw+Qgqj3+2GggqQEeQgZVeKfOqK/U0S1SHERbPAKYDQ7/a4IptoXGI7dqztkiGikwDU9bAFytpt/gRI97iyLF/hcfK4grwLcLX5WMpRlPCBEQBhzWUkxdvYJEDF4wbLyQF62nv+KxEAV5K3MSJWF5Hnf+fY67RU50N7bL08ViZ8QZ4FUkQxs06c6u+4g0OgeHwxs9YLqv2pyn9lAlCrEV9RJ1xFHG91Dd/OjJb5J57aO6jKf3UOIGxskkDyfFHjHZPqFDuIcoCZPoERIEPY2KwDVFvjCxjvCLNrUOKNjae/Mivo+wCd2JVh7sdX0O3PKY2QPF077GIFQoCUwMa8hUX5Swm4p6XJVcENhgPS7lZG1L+TF2+5vI+a/u/LK7Fkh/PbGVH/FtURN+njBczLPxu4SQOevKx/Oz3dOV2/4A7QHdLAK8Fkxw0I/FvhpCQN9Hs9OQvoh/3/CpCPNEACbnZwIpLHzlyC0PyhZIx4tYXE3PZvfuvspkB6FgBRSt8Um65nUOJg1g8qa0GQYeXJZCeLETw/5mZQsYDixbIZHGaI+LBcgsIGGQ/mJTgMcJq/ls3FSvZ/h4FDkIXI1rG/Adz0VZDmVyKYAAAAAElFTkSuQmCC
+
# Show address selection card
- kind: AdaptiveCardPrompt
id: selectAddressCard
@@ -216,34 +222,70 @@ beginDialog:
={
type: "AdaptiveCard",
'$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
- version: "1.3",
+ version: "1.5",
body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
{
type: "TextBlock",
- text: "Update Residential Address",
+ text: "Select an address to update",
weight: "Bolder",
size: "Medium",
wrap: true,
- color: "Default"
+ spacing: "Medium"
},
{
type: "TextBlock",
- text: "You have " & CountRows(Topic.homeAddresses) & " home addresses. Select the one you want to update.",
- wrap: true
+ text: "You have " & CountRows(Topic.homeAddresses) & " addresses. Select to update or add a new address.",
+ wrap: true,
+ spacing: "Small"
},
{
type: "Input.ChoiceSet",
id: "selectedAddress",
- label: "Select Address",
- style: "expanded",
+ label: "Address",
+ style: "compact",
isRequired: true,
errorMessage: "Please select an address.",
- choices: ForAll(Topic.addressChoices, { title: ThisRecord.title, value: ThisRecord.value })
+ choices: ForAll(Topic.addressChoices, { title: ThisRecord.title, value: ThisRecord.value }),
+ value: First(Topic.addressChoices).value
}
],
actions: [
- { type: "Action.Submit", title: "Continue" },
- { type: "Action.Submit", title: "Cancel", associatedInputs: "none" }
+ { type: "Action.Submit", title: "Continue", id: "Continue", data: { actionSubmitId: "Continue" } },
+ { type: "Action.Submit", title: "Add an address", id: "AddNew", data: { actionSubmitId: "AddNew" }, associatedInputs: "none" }
]
}
output:
@@ -268,12 +310,35 @@ beginDialog:
- kind: CancelAllDialogs
id: selectionCancelAll
- # Get the selected address details
- - kind: SetVariable
- id: setSelectedAddress
- displayName: Set selected address details
- variable: Topic.selectedAddress
- value: =LookUp(Topic.homeAddresses, AddressID = Topic.selectedAddressID)
+ # Handle add new address
+ - kind: ConditionGroup
+ id: handleAddNewAddress
+ conditions:
+ - id: addNewSelected
+ condition: =Topic.selectionActionId = "AddNew"
+ actions:
+ - kind: SetVariable
+ id: setIsNewAddressFromSelection
+ variable: Topic.isNewAddress
+ value: =true
+
+ - kind: SetVariable
+ id: clearSelectedAddressID
+ variable: Topic.selectedAddressID
+ value: =""
+
+ # Get the selected address details (only if not adding new)
+ - kind: ConditionGroup
+ id: checkIfContinueSelected
+ conditions:
+ - id: continueSelected
+ condition: =Topic.selectionActionId = "Continue"
+ actions:
+ - kind: SetVariable
+ id: setSelectedAddress
+ displayName: Set selected address details
+ variable: Topic.selectedAddress
+ value: =LookUp(Topic.homeAddresses, AddressID = Topic.selectedAddressID)
# Set current address values for form pre-population
- kind: SetVariable
@@ -322,7 +387,7 @@ beginDialog:
body: [
{
type: "TextBlock",
- text: "Update your home address",
+ text: "Update Your Home Address",
weight: "Bolder",
size: "Large"
},
@@ -334,31 +399,35 @@ beginDialog:
{
type: "Input.Text",
id: "addressLine1",
- label: "Address Line 1 ",
+ label: "Address line 1",
placeholder: "Street address",
isRequired: true,
+ errorMessage: "Address line 1 is required.",
value: If(IsBlank(Topic.currentAddressLine1), "", Topic.currentAddressLine1)
},
{
type: "Input.Text",
id: "addressLine2",
- label: "Address Line 2",
+ label: "Address line 2",
placeholder: "Apt, Suite, Unit, etc. (optional)",
value: If(IsBlank(Topic.currentAddressLine2), "", Topic.currentAddressLine2)
},
{
type: "Input.Text",
id: "city",
- label: "City ",
+ label: "City",
placeholder: "City",
isRequired: true,
+ errorMessage: "City is required.",
value: If(IsBlank(Topic.currentCity), "", Topic.currentCity)
},
{
type: "Input.ChoiceSet",
id: "country",
- label: "Country ",
+ label: "Country",
+ style: "compact",
isRequired: true,
+ errorMessage: "Please select a country.",
value: If(IsBlank(Topic.currentCountryCode), "USA", Topic.currentCountryCode),
choices: [
{ title: "United States", value: "USA" },
@@ -376,8 +445,10 @@ beginDialog:
{
type: "Input.ChoiceSet",
id: "stateProvince",
- label: "State/Province ",
+ label: "State/province",
+ style: "compact",
isRequired: true,
+ errorMessage: "Please select a state/province.",
value: If(IsBlank(Topic.currentStateProvince), "", Topic.currentStateProvince),
choices: [
{ title: "Alabama", value: "USA-AL" },
@@ -440,9 +511,10 @@ beginDialog:
{
type: "Input.Text",
id: "postalCode",
- label: "Postal/ZIP Code ",
- placeholder: "Postal Code",
+ label: "Postal/ZIP code",
+ placeholder: "Postal code",
isRequired: true,
+ errorMessage: "Postal code is required.",
value: If(IsBlank(Topic.currentPostalCode), "", Topic.currentPostalCode)
},
{
@@ -520,47 +592,133 @@ beginDialog:
- kind: EndDialog
id: endOnValidationError
- # Step 8: Call Update API
- - kind: BeginDialog
- id: updateAddress_BeginDialog
- displayName: Update Residential Address
- input:
- binding:
- parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Event_Effective_Date}"",""value"":"""& Text(Now(), "yyyy-MM-dd") &"""},{""key"":""{Address_ID}"",""value"":""" & Topic.selectedAddressID & """},{""key"":""{Country_Code}"",""value"":""" & Topic.newCountry & """},{""key"":""{State_Province_Code}"",""value"":""" & Topic.newStateProvince & """},{""key"":""{Address_Line_1}"",""value"":""" & Topic.newAddressLine1 & """},{""key"":""{Address_Line_2}"",""value"":""" & If(IsBlank(Topic.newAddressLine2), "", Topic.newAddressLine2) & """},{""key"":""{City}"",""value"":""" & Topic.newCity & """},{""key"":""{Postal_Code}"",""value"":""" & Topic.newPostalCode & """},{""key"":""{Is_Primary}"",""value"":""" & If(Topic.newIsPrimary = "true", "true", "false") & """}]}"
- scenarioName: msdyn_HRWorkdayHCMEmployeeUpdateResidentialAddress
+ # Step 8: Call Add or Update API based on isNewAddress flag
+ - kind: ConditionGroup
+ id: checkAddOrUpdate
+ conditions:
+ - id: isNewAddressCondition
+ condition: =Topic.isNewAddress = true
+ displayName: Add new address
+ actions:
+ # Call Add API (no Address_ID parameter)
+ - kind: BeginDialog
+ id: addAddress_BeginDialog
+ displayName: Add New Residential Address
+ input:
+ binding:
+ parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Event_Effective_Date}"",""value"":"""& Text(Now(), "yyyy-MM-dd") &"""},{""key"":""{Country_Code}"",""value"":""" & Topic.newCountry & """},{""key"":""{State_Province_Code}"",""value"":""" & Topic.newStateProvince & """},{""key"":""{Address_Line_1}"",""value"":""" & Topic.newAddressLine1 & """},{""key"":""{Address_Line_2}"",""value"":""" & If(IsBlank(Topic.newAddressLine2), "", Topic.newAddressLine2) & """},{""key"":""{City}"",""value"":""" & Topic.newCity & """},{""key"":""{Postal_Code}"",""value"":""" & Topic.newPostalCode & """},{""key"":""{Is_Primary}"",""value"":""" & If(Topic.newIsPrimary = "true", "true", "false") & """}]}"
+ scenarioName: msdyn_HRWorkdayHCMEmployeeAddResidentialAddress
- dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
- output:
- binding:
- errorResponse: Topic.updateErrorResponse
- isSuccess: Topic.updateIsSuccess
- workdayResponse: Topic.updateWorkdayResponse
+ dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
+ output:
+ binding:
+ errorResponse: Topic.updateErrorResponse
+ isSuccess: Topic.updateIsSuccess
+ workdayResponse: Topic.updateWorkdayResponse
- # Step 10: Show result
+ elseActions:
+ # Call Update API (with Address_ID parameter)
+ - kind: BeginDialog
+ id: updateAddress_BeginDialog
+ displayName: Update Residential Address
+ input:
+ binding:
+ parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Event_Effective_Date}"",""value"":"""& Text(Now(), "yyyy-MM-dd") &"""},{""key"":""{Address_ID}"",""value"":""" & Topic.selectedAddressID & """},{""key"":""{Country_Code}"",""value"":""" & Topic.newCountry & """},{""key"":""{State_Province_Code}"",""value"":""" & Topic.newStateProvince & """},{""key"":""{Address_Line_1}"",""value"":""" & Topic.newAddressLine1 & """},{""key"":""{Address_Line_2}"",""value"":""" & If(IsBlank(Topic.newAddressLine2), "", Topic.newAddressLine2) & """},{""key"":""{City}"",""value"":""" & Topic.newCity & """},{""key"":""{Postal_Code}"",""value"":""" & Topic.newPostalCode & """},{""key"":""{Is_Primary}"",""value"":""" & If(Topic.newIsPrimary = "true", "true", "false") & """}]}"
+ scenarioName: msdyn_HRWorkdayHCMEmployeeUpdateResidentialAddress
+
+ dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
+ output:
+ binding:
+ errorResponse: Topic.updateErrorResponse
+ isSuccess: Topic.updateIsSuccess
+ workdayResponse: Topic.updateWorkdayResponse
+
+ # Step 9: Show result
- kind: ConditionGroup
id: checkUpdateSuccess
conditions:
- id: updateSuccessCondition
condition: =Topic.updateIsSuccess = true
actions:
+ - kind: SendActivity
+ id: sendSuccessIntroMessage
+ activity: Great! You've updated your address.
+
- kind: SendActivity
id: sendSuccessMessage
- activity: |-
- ✅ Your home address has been successfully updated!
-
- **New Address:**
- {Topic.newAddressLine1}
- {If(!IsBlank(Topic.newAddressLine2), Topic.newAddressLine2 & Char(10), "")}
- {Topic.newCity}, {Topic.newStateProvince} {Topic.newPostalCode}
- {Topic.newCountry}
+ activity:
+ attachments:
+ - kind: AdaptiveCardTemplate
+ cardContent: |-
+ ={
+ type: "AdaptiveCard",
+ '$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
+ version: "1.5",
+ body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
+ {
+ type: "TextBlock",
+ text: "✅ Address updated",
+ weight: "Bolder",
+ size: "Medium",
+ wrap: true,
+ spacing: "Medium"
+ },
+ {
+ type: "TextBlock",
+ text: Topic.newAddressLine1 & ", " & Topic.newCity & ", " & Topic.newStateProvince & " " & Topic.newPostalCode & " (" & If(Topic.newIsPrimary = "true", "Primary", "Home") & ")",
+ wrap: true,
+ spacing: "Small"
+ }
+ ]
+ }
+
+ - kind: CancelAllDialogs
+ id: endOnSuccess
elseActions:
- kind: SendActivity
id: sendUpdateErrorMessage
activity: |-
- ❌ There was an error updating your address. Please try again later or contact support.
+ There was an error updating your address. Please try again later or contact support.
- Error: {Topic.updateErrorResponse}
+ **Error details:** {Topic.updateErrorResponse}
+
+ - kind: CancelAllDialogs
+ id: endOnUpdateError
inputType: {}
outputType:
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/README.md b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/README.md
new file mode 100644
index 00000000..4e0183f3
--- /dev/null
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/README.md
@@ -0,0 +1,177 @@
+# Request Time Off
+
+This scenario allows employees to submit time off requests to Workday, supporting single-day or multi-day date ranges with automatic balance display.
+
+## Overview
+
+The `WorkdayEmployeeRequestTimeOff` topic allows employees to:
+1. **View** their current leave balances (vacation, sick, floating holiday)
+2. **Submit** time off requests for a date range
+3. **Choose** the type of leave and hours per day
+
+## Flow
+
+```
+┌─────────────────────────────────────┐
+│ User triggers topic │
+│ "Request time off" │
+└──────────────┬──────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────┐
+│ Fetch current leave balances │
+│ (msdyn_HRWorkdayHCMEmployee │
+│ GetVacationBalance) │
+└──────────────┬──────────────────────┘
+ │
+ ▼
+┌─────────────────────────────────────┐
+│ Display Adaptive Card Form │
+│ - Shows available balances │
+│ - Time off type dropdown │
+│ - Start date / End date │
+│ - Hours per day │
+└──────────────┬──────────────────────┘
+ │
+ ▼
+ ┌──────┴──────┐
+ │ User │
+ │ Action? │
+ └──────┬──────┘
+ │
+ ┌───────┼───────┐
+ │ │ │
+ ▼ ▼ ▼
+┌──────────┐ ┌──────────┐ ┌──────────────┐
+│ Cancel │ │ Type Not │ │ Submit │
+│ │ │ Listed │ │ │
+└────┬─────┘ └────┬─────┘ └──────┬───────┘
+ │ │ │
+ ▼ ▼ ▼
+┌──────────┐ ┌──────────┐ ┌──────────────┐
+│ End │ │ Redirect │ │ Validate │
+│ Dialog │ │ to │ │ Dates │
+└──────────┘ │ Workday │ └──────┬───────┘
+ └──────────┘ │
+ ▼
+ ┌────────────────────────┐
+ │ Build date list │
+ │ (loop: start → end) │
+ └────────────┬───────────┘
+ │
+ ▼
+ ┌────────────────────────┐
+ │ Submit to Workday │
+ │ (msdyn_HRWorkday │
+ │ AbsenceEnterTimeOff │
+ │ _MultiDay) │
+ └────────────┬───────────┘
+ │
+ ┌───────┴───────┐
+ │ │
+ ▼ ▼
+ ┌──────────┐ ┌──────────────┐
+ │ Success │ │ Error │
+ │ Card │ │ (AI-friendly │
+ │ │ │ message) │
+ └──────────┘ └──────────────┘
+```
+
+## API Scenarios Used
+
+| Scenario | API | Purpose |
+|----------|-----|---------|
+| `msdyn_HRWorkdayHCMEmployeeGetVacationBalance` | Human_Resources | Fetch current leave balances |
+| `msdyn_HRWorkdayAbsenceEnterTimeOff_MultiDay` | Absence_Management v42.0 | Submit time off request |
+
+## Features
+
+### Intelligent Leave Type Mapping
+User input is automatically mapped to leave types using configurable keywords:
+
+| User Says | Maps To |
+|-----------|---------|
+| "vacation", "annual", "pto", "holiday pay" | Vacation_Hours |
+| "floating", "floater", "float day" | Floating_Holiday_Hours |
+| "sick", "illness", "medical", "unwell" | Sick_Hours |
+
+## Form Fields
+
+| Field | Type | Required | Default | Description |
+|-------|------|----------|---------|-------------|
+| Type of time off | Dropdown | Yes | Auto-mapped | Vacation, Floating holiday, Sick leave |
+| Start date | Date Input | Yes | From user query | First day of time off |
+| End date | Date Input | Yes | From user query | Last day of time off |
+| Hours per day | Number Input | Yes | 8 | Hours to deduct per day |
+
+## Input Parameters
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `InputStartDate` | DateTime | Pre-fill start date from user query |
+| `InputEndDate` | DateTime | Pre-fill end date from user query |
+| `InputHoursPerDay` | Number | Pre-fill hours per day |
+| `InputTimeOffType` | String | Natural language leave type (e.g., "vacation", "sick") |
+
+## XML Template Parameters
+
+| Parameter | Description | Example |
+|-----------|-------------|---------|
+| `{Employee_ID}` | Employee's Workday ID | `21514` |
+| `{timeoff_Dates}` | Comma-separated list of dates | `2025-09-15,2025-09-16,2025-09-17` |
+| `{timeoff_Time_Off_Type}` | Time off type ID | `Vacation_Hours` |
+| `{timeoff_Hours_Per_Day}` | Hours per day | `8` |
+| `{timeoff_Comment}` | Comment for the request | `ess generated time off request` |
+
+## Configuration
+
+### Leave Type Configuration
+Edit the `LeaveTypeConfig` variable to customize keyword-to-leave-type mappings:
+
+```yaml
+- kind: SetVariable
+ id: set_leave_type_config
+ variable: Topic.LeaveTypeConfig
+ value: |-
+ =Table(
+ {Keywords: "vacation,annual,pto,holiday pay", LeaveTypeValue: "Vacation_Hours"},
+ {Keywords: "floating,floater,float day", LeaveTypeValue: "Floating_Holiday_Hours"},
+ {Keywords: "sick,illness,medical,unwell,not feeling well", LeaveTypeValue: "Sick_Hours"}
+ )
+```
+
+### Plan Balance Configuration
+Edit the `PlanConfig` variable to map Workday Plan IDs to display names:
+
+```yaml
+- kind: SetVariable
+ id: set_plan_config
+ variable: Topic.PlanConfig
+ value: |-
+ =Table(
+ {PlanID: "PTO_USA", DisplayName: "Paid time off"},
+ {PlanID: "FH_USA", DisplayName: "Floating holiday"},
+ {PlanID: "ABSENCE_PLAN-6-159", DisplayName: "Sick leave"},
+ {PlanID: "ABSENCE_PLAN-6-158", DisplayName: "Vacation"}
+ )
+```
+
+### Workday URL Configuration
+Update the `WorkdayUrl` variable to point to your Workday tenant:
+
+```yaml
+- kind: SetVariable
+ id: set_workday_url
+ variable: Topic.WorkdayUrl
+ value: https://impl.workday.com//home.htmld
+```
+
+## Example Triggers
+
+**Valid requests:**
+- "Request time off"
+- "I need to submit time off"
+- "Please request vacation from January 5th to January 10th"
+- "Request sick leave for next week"
+- "I need time off from 2025-09-15 to 2025-09-20 for a family event"
+- "Book 4 hours of PTO tomorrow"
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/msdyn_HRWorkdayAbsenceEnterTimeOff_EnterTimeOffInfo.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/msdyn_HRWorkdayAbsenceEnterTimeOff_EnterTimeOffInfo.xml
deleted file mode 100644
index 4b8ad55e..00000000
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/msdyn_HRWorkdayAbsenceEnterTimeOff_EnterTimeOffInfo.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
- User
-
- msdyn_HRWorkdayAbsenceEnterTimeOff_EnterTimeOffInfo
- Absence_Management
- v42.0
-
-
-
-
- //*[local-name()='Time_Off_Event_Reference']/*[local-name()='ID' and @*[local-name()='type']='WID']
- WID
-
-
-
-
-
-
-
-
-
- false
- true
- true
-
- {Comment}
-
-
-
-
- {Employee_ID}
-
-
- {Time_Off_Date}
- {Hours}
-
- {Reason_ID}
-
- {Comment}
-
-
-
-
-
-
\ No newline at end of file
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/msdyn_HRWorkdayAbsenceEnterTimeOff_MultiDay.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/msdyn_HRWorkdayAbsenceEnterTimeOff_MultiDay.xml
new file mode 100644
index 00000000..7c6cc0ee
--- /dev/null
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/msdyn_HRWorkdayAbsenceEnterTimeOff_MultiDay.xml
@@ -0,0 +1,55 @@
+
+
+
+
+ User
+
+ msdyn_HRWorkdayAbsenceEnterTimeOff_MultiDay
+ Absence_Management
+ v42.0
+
+
+
+
+ //*[local-name()='Time_Off_Event_Reference']/*[local-name()='ID' and @*[local-name()='type']='WID']
+ Event_WID
+
+
+ //*[local-name()='Time_Off_Entry_Reference']
+ Entry_References
+
+
+
+
+
+
+
+
+
+ false
+ true
+ true
+
+ {timeoff_Comment}
+
+
+
+
+ {Employee_ID}
+
+
+
+
+ {timeoff_Date}
+ {timeoff_Hours_Per_Day}
+
+ {timeoff_Time_Off_Type}
+
+ {timeoff_Comment}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/topic.yaml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/topic.yaml
index 1921a489..67885e78 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/topic.yaml
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayEmployeeRequestTimeOff/topic.yaml
@@ -1,32 +1,39 @@
kind: AdaptiveDialog
inputs:
- kind: AutomaticTaskInput
- propertyName: TimeOffDate
- description: Date of time off (yyyy-mm-dd)
+ propertyName: EmployeeName
+ description: The name of the employee to fetch data for.
+ entity: PersonNamePrebuiltEntity
+ shouldPromptUser: false
+
+ - kind: AutomaticTaskInput
+ propertyName: InputStartDate
+ description: The start date of the time off request.
entity: DateTimePrebuiltEntity
shouldPromptUser: false
- kind: AutomaticTaskInput
- propertyName: NumberOfHours
- description: Number of hours for time off
- entity: NumberPrebuiltEntity
+ propertyName: InputEndDate
+ description: The end date of the time off request.
+ entity: DateTimePrebuiltEntity
shouldPromptUser: false
- kind: AutomaticTaskInput
- propertyName: ReasonText
- description: Reason for time off (free text)
+ propertyName: InputHoursPerDay
+ description: The number of hours per day for the time off request.
+ entity: NumberPrebuiltEntity
shouldPromptUser: false
- kind: AutomaticTaskInput
- propertyName: EmployeeName
- description: The name of the employee to fetch data for.
- entity: PersonNamePrebuiltEntity
+ propertyName: InputTimeOffType
+ description: Extract the type of leave mentioned such as vacation, sick, sick leave, floating holiday, floater, PTO, annual leave, medical, or illness. Extract keywords like 'sick', 'vacation', 'floating', 'PTO', 'annual'.
+ entity: StringPrebuiltEntity
shouldPromptUser: false
modelDescription: |-
You will respond only to requests related to requesting time off for the user making the request.
All time off requests are submitted to Workday (Absence_Management) and pertain exclusively to the requesting user.
- This topic may prompt the user for input (date, hours, and reason) if they are requesting time off for themselves.
+ This topic may prompt the user for input (time off type, start date, end date, and reason) if they are requesting time off for themselves.
This data exclusively belongs to the user making the request. Do not respond to questions about other people's data.
Example invalid requests:
@@ -37,13 +44,172 @@ modelDescription: |-
Example valid requests:
"Request time off"
"I need to submit time off"
- "Please request 8 hours time off on 2025-09-15 because of a family event"
- "Request 4 hours vacation on December 1st"
+ "Please request vacation from January 5th to January 10th"
+ "Request sick leave for next week"
+ "I need time off from 2025-09-15 to 2025-09-20 for a family event"
beginDialog:
kind: OnRecognizedIntent
id: main
intent: {}
actions:
+ - kind: SetVariable
+ id: set_workday_url
+ variable: Topic.WorkdayUrl
+ value: https://impl.workday.com//home.htmld
+
+ - kind: SetVariable
+ id: set_workday_icon_url
+ variable: Topic.WorkdayIconUrl
+ value: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAExUlEQVR4nOVbSUwUQRT9XSJxQVExLoQZLwJGGZfEJcY5KJx0Er2piF7d4hkTTby5njxoRE9eHM5oxqOY2O5jXFAjYFzAgBrEDKIxGpf8xta2+ld1z3T1TPfMSwiZ7vrd9V69/391D2jgEZWLd/6CAiPz6JyWa6wWVtKqxNCKhXiuQmjFRjxbIVgxk3czf+YlOCyQ8WC5BIURIj4sm8FhB8WLuRlUTOD5MdnJYoWVZ1nebjruGzRMHIbYhGFomPDB+Iw/iMyPcuj6WgWPv86A66NzjM/5gub36q+peAvN03phw9S+v4SdcP3zHGj/WAvtH+eD33sEzS8BouWjcKrmGqyZ/Dbna/R9q4AT75f5JkTGFEA1+d0zn8DhuXeUXQ8FODi4ypfUYCovhhY/HbmmlDyiefpzuDq/w3CVamgqHYCTjE0clo4Z+VkO+uhcw96Zn2MrioURyWFxlAFjNr1cb/xWBU0V+SPVt2FX1VPhebOoYYETAUVonfUA4hWDEBlPrzaSX/t8k7J00FQIsH/2fWPiFLC1HRhYJSUuEqJ5ei95/vJIFHa8boJA1IDon8mKVn3ji/VZkTdXed+bOBx/t4w8jy0V60IgBGiddV9IHkl4seqJ90uFIuB93e4rfBMgWj5KrkT/9wo4OLgSVABFaBtaRN57qwIXMD9Wf/urJqU9G0WgrpeY+rqwAjQQLe/yyDyj8KkEkm/7YHcB7jK97g3KvAS3D9fCY04EXC0/cHZoIVSyfw9QpjBe9wRaqTwC52UrHEYwKHEwKHEwKHEwKHGUeQnetnE1RKur/juWvHgT+gbEj7Wx+hpIrLO3SozBWBn2tDRC5ZRJWcX4KsDR1s3/TQgRrZ4Jew+dF8ZcOLnXJpqJru5+6Op+Q55D0Y62brEd19O90DcwBAVJgS5isrEFNcLx8eV1QvJj5+ulsTwyn754Iu9dgGf9tmMygmh/GRKN4l1kbEHEfn+BW/ImgJ7usR3DlMA0oJBopB9trQLxKWU9R6VM4ARAxJfXAg8kRtmYH0OlUKw+Qgqj3+2GggqQEeQgZVeKfOqK/U0S1SHERbPAKYDQ7/a4IptoXGI7dqztkiGikwDU9bAFytpt/gRI97iyLF/hcfK4grwLcLX5WMpRlPCBEQBhzWUkxdvYJEDF4wbLyQF62nv+KxEAV5K3MSJWF5Hnf+fY67RU50N7bL08ViZ8QZ4FUkQxs06c6u+4g0OgeHwxs9YLqv2pyn9lAlCrEV9RJ1xFHG91Dd/OjJb5J57aO6jKf3UOIGxskkDyfFHjHZPqFDuIcoCZPoERIEPY2KwDVFvjCxjvCLNrUOKNjae/Mivo+wCd2JVh7sdX0O3PKY2QPF077GIFQoCUwMa8hUX5Swm4p6XJVcENhgPS7lZG1L+TF2+5vI+a/u/LK7Fkh/PbGVH/FtURN+njBczLPxu4SQOevKx/Oz3dOV2/4A7QHdLAK8Fkxw0I/FvhpCQN9Hs9OQvoh/3/CpCPNEACbnZwIpLHzlyC0PyhZIx4tYXE3PZvfuvspkB6FgBRSt8Um65nUOJg1g8qa0GQYeXJZCeLETw/5mZQsYDixbIZHGaI+LBcgsIGGQ/mJTgMcJq/ls3FSvZ/h4FDkIXI1rG/Adz0VZDmVyKYAAAAAElFTkSuQmCC
+
+ # ================================================================
+ # DATE CONFIGURATION
+ # Set the effective date for balance lookup. Default is Today().
+ # Customers can change this to a specific date if needed.
+ # ================================================================
+ - kind: SetVariable
+ id: set_as_of_effective_date
+ variable: Topic.AsOfEffectiveDate
+ value: =Today()
+
+ # ================================================================
+ # LEAVE TYPE CONFIGURATION
+ # Edit keywords below to customize how user phrases map to leave types.
+ # Keywords are comma-separated and case-insensitive.
+ # LeaveTypeValue must match the dropdown choice values.
+ # ================================================================
+ - kind: SetVariable
+ id: set_leave_type_config
+ variable: Topic.LeaveTypeConfig
+ value: |-
+ =Table(
+ {Keywords: "vacation,annual,pto,holiday pay", LeaveTypeValue: "Vacation_Hours"},
+ {Keywords: "floating,floater,float day", LeaveTypeValue: "Floating_Holiday_Hours"},
+ {Keywords: "sick,illness,medical,unwell,not feeling well", LeaveTypeValue: "Sick_Hours"}
+ )
+
+ # Map extracted time off type to dropdown value using config table
+ - kind: SetVariable
+ id: set_mapped_time_off_type
+ variable: Topic.MappedTimeOffType
+ value: |-
+ =If(
+ IsBlank(Topic.InputTimeOffType),
+ "",
+ Coalesce(
+ First(
+ Filter(
+ Topic.LeaveTypeConfig,
+ !IsEmpty(Filter(Split(Keywords, ","), Trim(Value) in Lower(Topic.InputTimeOffType)))
+ )
+ ).LeaveTypeValue,
+ ""
+ )
+ )
+
+ - kind: BeginDialog
+ id: get_leave_balance
+ displayName: Get Leave Balance
+ input:
+ binding:
+ parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{As_Of_Effective_Date}"",""value"":""" & Text(Topic.AsOfEffectiveDate, "yyyy-MM-dd") & """}]}"
+ scenarioName: msdyn_HRWorkdayHCMEmployeeGetVacationBalance
+
+ dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
+ output:
+ binding:
+ errorResponse: Topic.balanceErrorResponse
+ isSuccess: Topic.balanceIsSuccess
+ workdayResponse: Topic.balanceResponse
+
+ - kind: ParseValue
+ id: parse_balance
+ variable: Topic.parsedBalance
+ valueType:
+ kind: Record
+ properties:
+ PlanDescriptor:
+ type:
+ kind: Table
+ properties:
+ Value: String
+
+ PlanID:
+ type:
+ kind: Table
+ properties:
+ Value: String
+
+ RemainingBalance:
+ type:
+ kind: Table
+ properties:
+ Value: String
+
+ UnitOfTime:
+ type:
+ kind: Table
+ properties:
+ Value: String
+
+ value: =Topic.balanceResponse
+
+ # ================================================================
+ # PLAN BALANCE CONFIGURATION
+ # Maps Plan IDs (from balance API) to display names.
+ # Update PlanID values to match your Workday configuration.
+ # Only plans listed here AND returned by the API will be displayed.
+ # ================================================================
+ - kind: SetVariable
+ id: set_plan_config
+ variable: Topic.PlanConfig
+ value: |-
+ =Table(
+ {PlanID: "PTO_USA", DisplayName: "Paid time off"},
+ {PlanID: "FH_USA", DisplayName: "Floating holiday"},
+ {PlanID: "ABSENCE_PLAN-6-159", DisplayName: "Sick leave"},
+ {PlanID: "ABSENCE_PLAN-6-158", DisplayName: "Vacation"}
+ )
+
+ # Create merged balance table for easy lookup by PlanID
+ - kind: SetVariable
+ id: set_balance_table
+ variable: Topic.BalanceTable
+ value: |-
+ =ForAll(
+ Sequence(CountRows(Topic.parsedBalance.PlanID)),
+ {
+ PlanID: Index(Topic.parsedBalance.PlanID, Value).Value,
+ Balance: Index(Topic.parsedBalance.RemainingBalance, Value).Value
+ }
+ )
+
+ # Build display data: only include plans that exist in BOTH config AND API response
+ - kind: SetVariable
+ id: set_display_balances
+ variable: Topic.DisplayBalances
+ value: |-
+ =ForAll(
+ Filter(
+ Topic.PlanConfig,
+ !IsBlank(LookUp(Topic.BalanceTable, PlanID = ThisRecord.PlanID).Balance)
+ ) As plan,
+ {
+ PlanID: plan.PlanID,
+ DisplayName: plan.DisplayName,
+ Balance: LookUp(Topic.BalanceTable, PlanID = plan.PlanID).Balance
+ }
+ )
+
+ - kind: SetVariable
+ id: build_intro_message
+ variable: Topic.introMessage
+ value: ="Sure, I'll help you submit a time off request. Here's a form where you can choose the type of leave and dates you want off. Don't see the type of leave you want? [Book directly in Workday](" & Topic.WorkdayUrl & ")"
+
+ - kind: SendActivity
+ id: intro_message
+ activity: "{Topic.introMessage}"
+
- kind: ConditionGroup
id: need_inputs
conditions:
@@ -52,88 +218,194 @@ beginDialog:
actions:
- kind: AdaptiveCardPrompt
id: collect_time_off
- displayName: Ask date, hours and reason for time off
+ displayName: Ask time off type, start date, end date and reason
card: |-
={
type: "AdaptiveCard",
'$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
- version: "1.3",
+ version: "1.5",
body: [
{
type: "TextBlock",
- text: "Request Time Off",
+ text: "Book your time off",
weight: "Bolder",
size: "Medium",
wrap: true,
color: "Default"
},
+ {
+ type: "Container",
+ style: "emphasis",
+ bleed: true,
+ items: [
+ {
+ type: "TextBlock",
+ text: "Available balance in hours as of " & Text(Topic.AsOfEffectiveDate, "mmmm d, yyyy"),
+ size: "Small",
+ weight: "Bolder",
+ wrap: true
+ },
+ {
+ type: "ColumnSet",
+ columns: ForAll(
+ Topic.DisplayBalances,
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ { type: "TextBlock", text: DisplayName, size: "Small", wrap: true },
+ { type: "TextBlock", text: Balance, weight: "Bolder", spacing: "Small" }
+ ]
+ }
+ )
+ }
+ ]
+ },
{
type: "TextBlock",
- text: "Enter the date, hours, and reason for your time off request.",
- wrap: true
+ text: "Fields marked with * are required.",
+ wrap: true,
+ spacing: "Medium",
+ size: "Small"
},
{
- type: "Input.ChoiceSet",
- id: "timeOffType",
- label: "Type of Time Off",
- style: "compact",
- isRequired: true,
- errorMessage: "Please select a type.",
- choices: [
- { title: "Floating Holiday", value: "Floating_Holiday_Hours" },
- { title: "Vacation", value: "Vacation_Hours" },
- { title: "Sick", value: "Sick_Hours" }
- ]
- },
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.ChoiceSet",
+ id: "timeOffType",
+ label: "Type of time off",
+ style: "compact",
+ value: Topic.MappedTimeOffType,
+ isRequired: true,
+ errorMessage: "Please select a type.",
+ choices: [
+ { title: "Vacation", value: "Vacation_Hours" },
+ { title: "Floating holiday", value: "Floating_Holiday_Hours" },
+ { title: "Sick leave", value: "Sick_Hours" },
+ { title: "I don't see my leave type listed", value: "NOT_LISTED" }
+ ]
+ }
+ ]
+ }
+ ]
+ },
{
type: "Input.Date",
- id: "timeOffDate",
- label: "Date",
+ id: "startDate",
+ label: "Start date",
+ value: If(IsBlank(Topic.InputStartDate), "", Text(Topic.InputStartDate, "yyyy-MM-dd")),
isRequired: true,
- errorMessage: "Please select a date.",
- value: If(IsBlank(Topic.TimeOffDate) || Topic.TimeOffDate < Today(), "",Text(Topic.TimeOffDate,"yyyy-MM-dd"))
+ errorMessage: "Please select a start date."
},
{
- type: "Input.Number",
- id: "numberOfHours",
- label: "Number of Hours",
- placeholder: "Enter hours (e.g., 8, 4, 2)",
+ type: "Input.Date",
+ id: "endDate",
+ label: "End date",
+ value: If(IsBlank(Topic.InputEndDate), "", Text(Topic.InputEndDate, "yyyy-MM-dd")),
isRequired: true,
- errorMessage: "Please enter the number of hours.",
- min: 0.5,
- max: 24,
- value: If(IsBlank(Topic.NumberOfHours), 8, Topic.NumberOfHours)
+ errorMessage: "Please select an end date."
},
{
- type: "Input.Text",
- id: "reasonText",
- placeholder: "Reason for time off",
- label: "Reason",
+ type: "Input.Number",
+ id: "hoursPerDay",
+ label: "Hours per day",
+ min: 1,
+ max: 24,
+ value: If(IsBlank(Topic.InputHoursPerDay), 8, Value(Topic.InputHoursPerDay)),
isRequired: true,
- maxLength: 500,
- errorMessage: "Reason is required.",
- value: Topic.ReasonText
+ errorMessage: "Please enter hours per day."
+ },
+ {
+ type: "ColumnSet",
+ spacing: "Medium",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "ActionSet",
+ actions: [
+ { type: "Action.Submit", title: "Submit", id: "Submit" },
+ { type: "Action.Submit", title: "Cancel", id: "Cancel" }
+ ]
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "stretch",
+ items: [],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "ColumnSet",
+ spacing: "None",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ color: "#242424",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ }
+ ],
+ verticalContentAlignment: "Center"
+ }
+ ]
}
],
- actions: [
- { type: "Action.Submit", title: "Submit" },
- { type: "Action.Submit", title: "Cancel", associatedInputs: "none" }
- ]
+ actions: []
}
output:
binding:
actionSubmitId: Topic.actionSubmitId
- numberOfHours: Topic.numberOfHours
- reasonText: Topic.reasonText
- timeOffDate: Topic.timeOffDate
+ endDate: Topic.endDate
+ hoursPerDay: Topic.hoursPerDay
+ startDate: Topic.startDate
timeOffType: Topic.timeOffType
outputType:
properties:
actionSubmitId: String
- numberOfHours: Number
- reasonText: String
- timeOffDate: String
+ endDate: String
+ hoursPerDay: String
+ startDate: String
timeOffType: String
- kind: ConditionGroup
@@ -149,13 +421,128 @@ beginDialog:
- kind: CancelAllDialogs
id: cancel_all
+ # Handle "I don't see my leave type listed" selection
+ - kind: ConditionGroup
+ id: handle_not_listed
+ conditions:
+ - id: type_not_listed
+ condition: =Topic.timeOffType = "NOT_LISTED"
+ actions:
+ - kind: SetVariable
+ id: set_not_listed_message
+ variable: Topic.notListedMessage
+ value: ="Since your leave type isn't listed here, you can book directly in [Workday](" & Topic.WorkdayUrl & "), or let me know if you want to change your type."
+
+ - kind: SendActivity
+ id: not_listed_msg
+ activity: "{Topic.notListedMessage}"
+
+ - kind: CancelAllDialogs
+ id: end_not_listed
+
+ # Validate end date >= start date
+ - kind: ConditionGroup
+ id: validate_dates
+ conditions:
+ - id: end_before_start
+ condition: =DateValue(Topic.endDate) < DateValue(Topic.startDate)
+ actions:
+ - kind: SendActivity
+ id: date_error_msg
+ activity: The end date can't be earlier than the start date.
+
+ # Ask user if they want to try again
+ - kind: Question
+ id: ask_retry_dates
+ interruptionPolicy:
+ allowInterruption: false
+ variable: Topic.retryDateChoice
+ prompt: Would you like to try with different dates?
+ entity: BooleanPrebuiltEntity
+
+ - kind: ConditionGroup
+ id: handle_retry_date_choice
+ conditions:
+ - id: user_wants_retry_dates
+ condition: =Topic.retryDateChoice = true
+ actions:
+ - kind: GotoAction
+ id: goto_form_on_date_retry
+ actionId: collect_time_off
+ elseActions:
+ - kind: SendActivity
+ id: end_on_no_date_retry
+ activity: No problem! Let me know if you need anything else.
+
+ - kind: CancelAllDialogs
+ id: cancel_on_no_date_retry
+
+ # ========================================================
+ # V3: Build list of dates and pass to Plugin
+ # ========================================================
+
+ # Initialize date list (empty string)
+ - kind: SetVariable
+ id: init_date_list
+ variable: Topic.dateList
+ value: =""
+
+ # Initialize loop counter
+ - kind: SetVariable
+ id: init_iterator
+ variable: Topic.newIterator
+ value: =0
+
+ # Set up loop variable
+ - kind: SetVariable
+ id: set_iterator
+ variable: Topic.iterator
+ value: =Topic.newIterator
+
+ # Calculate current date for this iteration
+ - kind: SetVariable
+ id: calc_current_date
+ variable: Topic.currentDate
+ value: =Text(DateAdd(DateValue(Topic.startDate), Topic.iterator, TimeUnit.Days), "yyyy-MM-dd")
+
+ # Loop to build comma-separated date list
+ - kind: ConditionGroup
+ id: build_date_list_loop
+ conditions:
+ - id: should_continue_building
+ condition: =DateValue(Topic.currentDate) <= DateValue(Topic.endDate)
+ actions:
+ # Append date to list (with comma separator if not first)
+ - kind: SetVariable
+ id: append_date
+ variable: Topic.dateList
+ value: =If(Topic.dateList = "", Topic.currentDate, Topic.dateList & "," & Topic.currentDate)
+
+ # Increment counter
+ - kind: SetVariable
+ id: increment_iterator
+ variable: Topic.newIterator
+ value: =Topic.newIterator + 1
+
+ # Continue loop
+ - kind: GotoAction
+ id: goto_build_loop
+ actionId: set_iterator
+
+ # Total days is the count from loop
+ - kind: SetVariable
+ id: calc_total_days
+ variable: Topic.totalDays
+ value: =Topic.newIterator
+
+ # Make single API call - Plugin will build XML entries from date list
- kind: BeginDialog
- id: execute_workday
- displayName: Redirect to Workday System Get Common Execution
+ id: execute_workday_multiday
+ displayName: Submit Multi-Day Time Off Request
input:
binding:
- parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Time_Off_Date}"",""value"":""" & Topic.timeOffDate & """},{""key"":""{Comment}"",""value"":""" & Topic.reasonText & """},{""key"":""{Reason_ID}"",""value"":""" & Topic.timeOffType & """},{""key"":""{Hours}"",""value"":""" & Text(Topic.numberOfHours) & """}]}"
- scenarioName: msdyn_HRWorkdayAbsenceEnterTimeOff_EnterTimeOffInfo
+ parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{timeoff_Dates}"",""value"":""" & Topic.dateList & """},{""key"":""{timeoff_Time_Off_Type}"",""value"":""" & Topic.timeOffType & """},{""key"":""{timeoff_Hours_Per_Day}"",""value"":""" & Topic.hoursPerDay & """},{""key"":""{timeoff_Comment}"",""value"":""ess generated time off request""}]}"
+ scenarioName: msdyn_HRWorkdayAbsenceEnterTimeOff_MultiDay
dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
output:
@@ -164,20 +551,191 @@ beginDialog:
isSuccess: Topic.isSuccess
workdayResponse: Topic.workdayResponse
+ # Parse error message for display
+ - kind: SetVariable
+ id: init_last_error
+ variable: Topic.lastErrorMessage
+ value: =If(Topic.isSuccess = true, "", Topic.errorResponse)
+
+ - kind: SetVariable
+ id: parse_error_message
+ variable: Topic.friendlyErrorMessage
+ value: =IfError(Text(ParseJSON(Topic.lastErrorMessage).error.message), IfError(Text(ParseJSON(Topic.lastErrorMessage).message), Topic.lastErrorMessage))
+
- kind: ConditionGroup
id: report_result
conditions:
- - id: failed
+ - id: request_failed
condition: =Topic.isSuccess = false
actions:
+ # Use AI to generate a friendly, conversational error message
+ - kind: AnswerQuestionWithAI
+ id: generate_friendly_error
+ autoSend: false
+ variable: Topic.aiGeneratedError
+ userInput: =Topic.friendlyErrorMessage
+ additionalInstructions: Reframe the following Workday error message in a friendly way for an employee. Keep it to ONE short sentence describing what went wrong. Do NOT include suggestions or next steps. Do NOT apologize. Do NOT use technical jargon. Example output format - "The dates you selected conflict with an existing request."
+
+ # Set final error message with fallback
+ - kind: SetVariable
+ id: set_final_error_message
+ variable: Topic.finalErrorMessage
+ value: =If(IsBlank(Topic.aiGeneratedError), "The dates you selected aren't available.", Topic.aiGeneratedError)
+
- kind: SendActivity
- id: failure_msg
- activity: An error occurred and your time off request was not submitted.
+ id: friendly_error_message
+ activity: "{Topic.finalErrorMessage}"
+
+ # Ask user if they want to try again
+ - kind: Question
+ id: ask_retry
+ interruptionPolicy:
+ allowInterruption: false
+ variable: Topic.retryChoice
+ prompt: Would you like to try with different dates?
+ entity: BooleanPrebuiltEntity
+
+ - kind: ConditionGroup
+ id: handle_retry_choice
+ conditions:
+ - id: user_wants_retry
+ condition: =Topic.retryChoice = true
+ actions:
+ - kind: GotoAction
+ id: goto_form_on_retry
+ actionId: collect_time_off
+ elseActions:
+ - kind: SendActivity
+ id: end_on_no_retry
+ activity: No problem! Let me know if you need anything else.
+
+ - kind: CancelAllDialogs
+ id: cancel_on_no_retry
elseActions:
- kind: SendActivity
- id: success_msg
- activity: Your time off request has been submitted.
+ id: success_card
+ activity:
+ attachments:
+ - kind: AdaptiveCardTemplate
+ cardContent: |-
+ ={
+ type: "AdaptiveCard",
+ '$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
+ version: "1.5",
+ body: [
+ {
+ type: "TextBlock",
+ text: "✅ Request submitted",
+ weight: "Bolder",
+ size: "Medium",
+ wrap: true
+ },
+ {
+ type: "TextBlock",
+ text: "Your time off request has been successfully submitted and is now pending approval.",
+ wrap: true,
+ spacing: "Small"
+ },
+ {
+ type: "Table",
+ spacing: "Medium",
+ showGridLines: false,
+ firstRowAsHeader: false,
+ columns: [
+ { width: 1 },
+ { width: 2 }
+ ],
+ rows: [
+ {
+ type: "TableRow",
+ cells: [
+ {
+ type: "TableCell",
+ items: [{ type: "TextBlock", text: "Type of time off", weight: "Bolder" }]
+ },
+ {
+ type: "TableCell",
+ items: [{ type: "TextBlock", text: Switch(Topic.timeOffType, "Vacation_Hours", "Vacation", "Floating_Holiday_Hours", "Floating holiday", "Sick_Hours", "Sick leave", Topic.timeOffType), wrap: true }]
+ }
+ ]
+ },
+ {
+ type: "TableRow",
+ cells: [
+ {
+ type: "TableCell",
+ items: [{ type: "TextBlock", text: "Time off date range", weight: "Bolder" }]
+ },
+ {
+ type: "TableCell",
+ items: [{ type: "TextBlock", text: Text(DateValue(Topic.startDate), "mmmm d, yyyy") & " to " & Text(DateValue(Topic.endDate), "mmmm d, yyyy") & " (" & Text(Topic.totalDays) & " days)", wrap: true }]
+ }
+ ]
+ },
+ {
+ type: "TableRow",
+ cells: [
+ {
+ type: "TableCell",
+ items: [{ type: "TextBlock", text: "Total hours", weight: "Bolder" }]
+ },
+ {
+ type: "TableCell",
+ items: [{ type: "TextBlock", text: Text(Topic.totalDays * Value(Topic.hoursPerDay)) & " hours (" & Text(Topic.totalDays) & " x " & Topic.hoursPerDay & "-hour days)", wrap: true }]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ type: "Container",
+ horizontalAlignment: "Right",
+ items: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ color: "#242424",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ actions: []
+ }
+
+ - kind: SendActivity
+ id: follow_up_msg
+ activity: Can I help you submit another request?
- kind: CancelAllDialogs
id: end_dialogs
@@ -188,20 +746,21 @@ inputType:
displayName: EmployeeName
description: The name of the employee to fetch data for.
type: String
-
- NumberOfHours:
- displayName: NumberOfHours
- description: Number of hours for time off
+ InputStartDate:
+ displayName: InputStartDate
+ description: The start date of the time off request.
+ type: DateTime
+ InputEndDate:
+ displayName: InputEndDate
+ description: The end date of the time off request.
+ type: DateTime
+ InputHoursPerDay:
+ displayName: InputHoursPerDay
+ description: The number of hours per day for the time off request.
type: Number
-
- ReasonText:
- displayName: ReasonText
- description: Reason for time off (free text)
+ InputTimeOffType:
+ displayName: InputTimeOffType
+ description: The type of time off being requested.
type: String
- TimeOffDate:
- displayName: TimeOffDate
- description: Date of time off (yyyy-mm-dd)
- type: DateTime
-
outputType: {}
\ No newline at end of file
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayGetUserProfile/topic.yaml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayGetUserProfile/topic.yaml
index 79909aea..1744d76f 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayGetUserProfile/topic.yaml
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayGetUserProfile/topic.yaml
@@ -1,16 +1,23 @@
kind: AdaptiveDialog
modelDescription: |-
- Respond to user's profile information requests from Workday. Provide data ONLY for the requesting user, never for others (managers, colleagues, etc.).
+ Available fields: Name, Employee ID, DOB, Gender, Business Title, Organization (Department), Manager, Location, Hire Date, Work Email, Work Phone, Home Email, Home Phone, Home Address, Employment Status
+ For FULL PROFILE:
+ Heading - "Your employee profile"
+ Introduction - "Here's what I found in Workday, an HR platform your company uses."
+ Sections: Personal information, Hiring details, Role and work.
- Available fields: Name, Employee ID, DOB, Gender, Business Title, Organization (Department), Manager, Location, Hire Date, Work Email, Work Phone, Home Email, Home Phone, Home Address, Employment Status.
-
- Answer based on which specific data the user asks for. Include relevant fields based on the question.
-
- Include Continuous Service Date and Length of Service ONLY when user specifically asks about tenure, service length, years of service, or how long they've been with the company.
-
- Invalid requests: "What is my manager's job title?" "What is my colleague's employee ID?" "What department is John in?"
- Valid requests: "What is my employee ID?" "What is my job title?" "Show my profile" "What is my work email?" "What is my tenure?" (include service length)
+ For TENURE/POSITION:
+ Heading - "Time in your position"
+ Introduction: "You've been in your current role as a [Position] for [LengthOfService]. I pulled this from Workday, an HR platform your company uses."
+ Sections: "About your position"
+ Common Rules (Strict):
+ - Large heading & section line after it,
+ - Use sections mentioned as headers & bullets within, do not bold bullet points.
+ - ADDRESS IN ONE ROW
+ - Introduction - Right after heading
+ - Answer only based on what the user explicitly asks.
+ - Include only relevant fields, not the full profile unless requested.
beginDialog:
kind: OnRecognizedIntent
id: main
@@ -185,7 +192,7 @@ beginDialog:
Location: First(Topic.parsedWorkdayResponse.Location).Value,
HireDate: First(Topic.parsedWorkdayResponse.HireDate).Value,
WorkEmail: First(Topic.parsedWorkdayResponse.WorkEmail).Value,
- HomeAddress: First(Topic.parsedWorkdayResponse.HomeAddress).Value,
+ HomeAddress: Substitute(Substitute(Concat(Topic.parsedWorkdayResponse.HomeAddress, Value, ", "), Char(10), ", "), Char(13), ""),
HomeEmail: First(Topic.parsedWorkdayResponse.HomeEmail).Value,
HomePhone: First(Topic.parsedWorkdayResponse.HomePhone).Value,
WorkPhone: First(Topic.parsedWorkdayResponse.WorkPhone).Value,
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/README.md b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/README.md
index f33b21ec..449b82a3 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/README.md
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/README.md
@@ -1,12 +1,13 @@
# Workday Manage Emergency Contact
-This scenario enables employees to manage their emergency contacts in Workday through a conversational interface. It supports both adding new emergency contacts and updating existing ones.
+This scenario enables employees to manage their emergency contacts in Workday through a conversational interface. It supports adding new emergency contacts, updating existing ones, and deleting contacts.
## Features
- **View Existing Contacts**: Displays a list of the employee's current emergency contacts with primary contact marked with ⭐
- **Add New Contact**: Allows employees to add a new emergency contact
- **Update Existing Contact**: Allows employees to update details of an existing emergency contact
+- **Delete Contact**: Allows employees to remove an emergency contact from their profile
- **Primary Contact Management**: Set or change the primary emergency contact
- **Priority Assignment**: Assign priority levels (1-10) to contacts
@@ -20,6 +21,8 @@ Users can activate this topic with phrases like:
- "Edit my emergency contact details"
- "Who is my emergency contact?"
- "Show my emergency contacts"
+- "Delete my emergency contact"
+- "Remove an emergency contact"
## Files
@@ -29,13 +32,14 @@ Users can activate this topic with phrases like:
| `msdyn_HRWorkdayHCMEmployeeGetEmergencyContactInfo.xml` | XML template to fetch existing emergency contacts using Get_Workers API |
| `msdyn_HRWorkdayHCMEmployeeAddEmergencyContact.xml` | XML template to add a new emergency contact |
| `msdyn_HRWorkdayHCMEmployeeUpdateEmergencyContact.xml` | XML template to update an existing emergency contact |
+| `msdyn_HRWorkdayDeleteEmergencyContact.xml` | XML template to delete an existing emergency contact |
## Workday APIs Used
| API | Service | Version | Purpose |
|-----|---------|---------|---------|
| `Get_Workers` | Human_Resources | v45.0 | Retrieve employee's existing emergency contacts |
-| `Change_Emergency_Contacts` | Human_Resources | v45.0 | Add or update emergency contact information |
+| `Change_Emergency_Contacts` | Human_Resources | v45.0 | Add, update, or delete emergency contact information |
## Data Collected
@@ -90,21 +94,26 @@ The topic collects the following information for each emergency contact:
│ ⭐ Primary Contact │ │ │
│ • Other Contacts │ │ │
│ ➕ Add New Contact │ │ │
+ │ 🗑️ Delete Contact │ │ │
└───────────────────────┘ └─────────────────┘
│ │
▼ │
┌───────────────────────┐ │
│ User Selects │ │
- │ Contact or Add New │ │
+ │ Action │ │
└───────────────────────┘ │
│ │
- ▼ ▼
-┌─────────────────────────────────────────────────────────────┐
-│ Show Add/Update Form │
-│ (Pre-filled if updating existing) │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
+ ┌───────┼───────┐ │
+ │ │ │ │
+ ▼ ▼ ▼ ▼
+┌─────────┐ ┌─────────┐ ┌─────────────────────┐
+│ Add │ │ Update │ │ Delete │
+│ Form │ │ Form │ │ Confirmation │
+└─────────┘ └─────────┘ └─────────────────────┘
+ │ │ │
+ └───────┴────────────────┘
+ │
+ ▼
┌─────────────────────────────────────────────────────────────┐
│ Submit to Workday │
│ (Change_Emergency_Contacts API) │
@@ -150,3 +159,4 @@ The topic includes error handling for:
| Version | Date | Changes |
|---------|------|---------|
| 1.0 | December 2025 | Initial release with Add/Update functionality |
+| 1.1 | February 2026 | Added Delete functionality for removing emergency contacts |
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayDeleteEmergencyContact.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayDeleteEmergencyContact.xml
new file mode 100644
index 00000000..0a762798
--- /dev/null
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayDeleteEmergencyContact.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+ User
+
+ Template_DeleteEmergencyContactRequest
+ Human_Resources
+ v45.0
+
+
+
+ //*[local-name()='Emergency_Contact_Event_Reference']/*[local-name()='ID'][@*[local-name()='type']='WID']/text()
+ EventID
+
+
+
+
+
+
+
+
+
+ false
+ true
+ true
+
+ {Comment}
+
+ {Employee_ID}
+
+
+
+
+
+ {Employee_ID}
+
+ false
+
+
+ {Emergency_Contact_WID}
+
+ true
+
+ false
+ {Priority}
+
+ {Relationship_Type}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeAddEmergencyContact.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeAddEmergencyContact.xml
index 42b0f04f..8d4bcf05 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeAddEmergencyContact.xml
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeAddEmergencyContact.xml
@@ -89,7 +89,7 @@
-
+ =
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeUpdateEmergencyContact.xml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeUpdateEmergencyContact.xml
index d35d012a..e6928dc4 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeUpdateEmergencyContact.xml
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/msdyn_HRWorkdayHCMEmployeeUpdateEmergencyContact.xml
@@ -22,7 +22,7 @@
- true
+ false
true
true
diff --git a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/topic.yaml b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/topic.yaml
index ef27dce3..b88a44e0 100644
--- a/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/topic.yaml
+++ b/EmployeeSelfServiceAgent/Workday/EmployeeScenarios/WorkdayManageEmergencyContact/topic.yaml
@@ -1,4 +1,11 @@
kind: AdaptiveDialog
+inputs:
+ - kind: AutomaticTaskInput
+ propertyName: InputAction
+ description: "Look for keywords 'add', 'new', or 'create' in the user's request. If found, extract 'add'. Otherwise extract 'manage'."
+ entity: StringPrebuiltEntity
+ shouldPromptUser: false
+
modelDescription: |-
You will respond to requests related to managing emergency contacts for the user making the request.
This includes adding new emergency contacts or updating existing ones.
@@ -14,11 +21,17 @@ modelDescription: |-
"Update my emergency contact"
"Add or update emergency contact"
"Change my emergency contact information"
+ "Add a new emergency contact"
beginDialog:
kind: OnRecognizedIntent
id: main
intent: {}
actions:
+ - kind: SetVariable
+ id: set_workday_icon_url_2
+ variable: Topic.WorkdayIconUrl
+ value: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAExUlEQVR4nOVbSUwUQRT9XSJxQVExLoQZLwJGGZfEJcY5KJx0Er2piF7d4hkTTby5njxoRE9eHM5oxqOY2O5jXFAjYFzAgBrEDKIxGpf8xta2+ld1z3T1TPfMSwiZ7vrd9V69/391D2jgEZWLd/6CAiPz6JyWa6wWVtKqxNCKhXiuQmjFRjxbIVgxk3czf+YlOCyQ8WC5BIURIj4sm8FhB8WLuRlUTOD5MdnJYoWVZ1nebjruGzRMHIbYhGFomPDB+Iw/iMyPcuj6WgWPv86A66NzjM/5gub36q+peAvN03phw9S+v4SdcP3zHGj/WAvtH+eD33sEzS8BouWjcKrmGqyZ/Dbna/R9q4AT75f5JkTGFEA1+d0zn8DhuXeUXQ8FODi4ypfUYCovhhY/HbmmlDyiefpzuDq/w3CVamgqHYCTjE0clo4Z+VkO+uhcw96Zn2MrioURyWFxlAFjNr1cb/xWBU0V+SPVt2FX1VPhebOoYYETAUVonfUA4hWDEBlPrzaSX/t8k7J00FQIsH/2fWPiFLC1HRhYJSUuEqJ5ei95/vJIFHa8boJA1IDon8mKVn3ji/VZkTdXed+bOBx/t4w8jy0V60IgBGiddV9IHkl4seqJ90uFIuB93e4rfBMgWj5KrkT/9wo4OLgSVABFaBtaRN57qwIXMD9Wf/urJqU9G0WgrpeY+rqwAjQQLe/yyDyj8KkEkm/7YHcB7jK97g3KvAS3D9fCY04EXC0/cHZoIVSyfw9QpjBe9wRaqTwC52UrHEYwKHEwKHEwKHEwKHGUeQnetnE1RKur/juWvHgT+gbEj7Wx+hpIrLO3SozBWBn2tDRC5ZRJWcX4KsDR1s3/TQgRrZ4Jew+dF8ZcOLnXJpqJru5+6Op+Q55D0Y62brEd19O90DcwBAVJgS5isrEFNcLx8eV1QvJj5+ulsTwyn754Iu9dgGf9tmMygmh/GRKN4l1kbEHEfn+BW/ImgJ7usR3DlMA0oJBopB9trQLxKWU9R6VM4ARAxJfXAg8kRtmYH0OlUKw+Qgqj3+2GggqQEeQgZVeKfOqK/U0S1SHERbPAKYDQ7/a4IptoXGI7dqztkiGikwDU9bAFytpt/gRI97iyLF/hcfK4grwLcLX5WMpRlPCBEQBhzWUkxdvYJEDF4wbLyQF62nv+KxEAV5K3MSJWF5Hnf+fY67RU50N7bL08ViZ8QZ4FUkQxs06c6u+4g0OgeHwxs9YLqv2pyn9lAlCrEV9RJ1xFHG91Dd/OjJb5J57aO6jKf3UOIGxskkDyfFHjHZPqFDuIcoCZPoERIEPY2KwDVFvjCxjvCLNrUOKNjae/Mivo+wCd2JVh7sdX0O3PKY2QPF077GIFQoCUwMa8hUX5Swm4p6XJVcENhgPS7lZG1L+TF2+5vI+a/u/LK7Fkh/PbGVH/FtURN+njBczLPxu4SQOevKx/Oz3dOV2/4A7QHdLAK8Fkxw0I/FvhpCQN9Hs9OQvoh/3/CpCPNEACbnZwIpLHzlyC0PyhZIx4tYXE3PZvfuvspkB6FgBRSt8Um65nUOJg1g8qa0GQYeXJZCeLETw/5mZQsYDixbIZHGaI+LBcgsIGGQ/mJTgMcJq/ls3FSvZ/h4FDkIXI1rG/Adz0VZDmVyKYAAAAAElFTkSuQmCC
+
- kind: ConditionGroup
id: check_country_codes
conditions:
@@ -51,6 +64,25 @@ beginDialog:
dialog: msdyn_copilotforemployeeselfservicehr.topic.GetReferenceData
+ # Check if user explicitly wants to add a new contact - skip loading existing contacts
+ - kind: ConditionGroup
+ id: check_direct_add
+ conditions:
+ - id: user_wants_add_directly
+ condition: =(!IsBlank(Topic.InputAction) && "add" in Lower(Topic.InputAction)) || "add" in Lower(System.Activity.Text) || "new emergency contact" in Lower(System.Activity.Text) || "create" in Lower(System.Activity.Text)
+ displayName: User wants to add a new contact directly
+ actions:
+ - kind: SetVariable
+ id: set_add_mode_direct
+ variable: Topic.isUpdateMode
+ value: =false
+ - kind: SendActivity
+ id: direct_add_msg
+ activity: Sure. I can help you with that. Here's where you can add an emergency contact. You can also view all emergency contact information in Workday, your company's HR portal.
+ - kind: GotoAction
+ id: goto_add_form_direct
+ actionId: emergency_contact_form
+
- kind: BeginDialog
id: fetch_emergency_contacts
displayName: Fetch existing emergency contacts
@@ -226,20 +258,26 @@ beginDialog:
actions:
- kind: SetVariable
id: build_selection_choices
- displayName: Build selection choices with Add New option
+ displayName: Build selection choices
variable: Topic.selectionChoices
value: |
- =Table(
- ForAll(
- SortByColumns(Topic.contactSelectionList, "IsPrimary", SortOrder.Descending, "Priority", SortOrder.Ascending),
- {
- title: If(ThisRecord.IsPrimary = "1" || ThisRecord.IsPrimary = "true", "⭐ ", "") & ThisRecord.DisplayName & " (" & ThisRecord.RelationshipType & ") - " & Coalesce(ThisRecord.Phone, "No phone"),
- value: ThisRecord.WID
- }
- ),
- { title: "➕ Add New Emergency Contact", value: "ADD_NEW" }
+ =ForAll(
+ SortByColumns(Topic.contactSelectionList, "IsPrimary", SortOrder.Descending, "Priority", SortOrder.Ascending),
+ {
+ title: ThisRecord.DisplayName,
+ value: ThisRecord.WID
+ }
)
+ - kind: SetVariable
+ id: set_intro_msg_text
+ variable: Topic.introMsgText
+ value: ="Sure, I can help you with that. Here's where you can both update and add emergency contacts. I've identified " & Text(CountRows(Topic.contactSelectionList)) & " contacts of yours from [Workday](https://impl.workday.com/microsoft_dpt6/d/home.htmld), an HR platform your company uses."
+
+ - kind: SendActivity
+ id: intro_selection_msg
+ activity: "{Topic.introMsgText}"
+
- kind: AdaptiveCardPrompt
id: select_contact_card
displayName: Select emergency contact to update
@@ -247,34 +285,69 @@ beginDialog:
={
type: "AdaptiveCard",
'$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
- version: "1.3",
+ version: "1.5",
body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
{
type: "TextBlock",
- text: "Manage Emergency Contacts",
+ text: "Select an emergency contact to update",
weight: "Bolder",
size: "Medium",
wrap: true,
- color: "Default"
+ spacing: "Medium"
},
{
type: "TextBlock",
- text: "You have " & CountRows(Topic.contactSelectionList) & " emergency contact(s). Select one to update or add a new contact.",
- wrap: true
+ text: "You have " & CountRows(Topic.contactSelectionList) & " emergency contact(s). Select to update or add a new contact.",
+ wrap: true,
+ spacing: "Small"
},
{
type: "Input.ChoiceSet",
id: "selectedContact",
- label: "Select Emergency Contact",
- style: "expanded",
+ label: "Emergency contact",
+ style: "compact",
isRequired: true,
- errorMessage: "Please select an option.",
+ errorMessage: "Please select an emergency contact.",
choices: ForAll(Topic.selectionChoices, { title: ThisRecord.title, value: ThisRecord.value })
}
],
actions: [
- { type: "Action.Submit", title: "Continue" },
- { type: "Action.Submit", title: "Cancel", associatedInputs: "none" }
+ { type: "Action.Submit", title: "Continue", id: "Continue" },
+ { type: "Action.Submit", title: "Add an emergency contact", id: "ADD_NEW", associatedInputs: "none" }
]
}
output:
@@ -304,7 +377,7 @@ beginDialog:
id: set_mode
conditions:
- id: is_update_mode
- condition: =Topic.selectedContactWID <> "ADD_NEW"
+ condition: =Topic.selectionActionId = "Continue"
displayName: Update existing contact
actions:
- kind: SetVariable
@@ -333,6 +406,22 @@ beginDialog:
id: no_contacts_msg
activity: You don't have any emergency contacts configured yet. Let's add one now.
+ # Show context message before form (only for update mode)
+ - kind: ConditionGroup
+ id: show_update_context_msg
+ conditions:
+ - id: is_update_show_msg
+ condition: =Topic.isUpdateMode = true
+ actions:
+ - kind: SetVariable
+ id: set_update_context_text
+ variable: Topic.updateContextText
+ value: ="You've pulled up " & Topic.selectedContactData.FirstName & " " & Topic.selectedContactData.LastName & "'s emergency contact details. In this form you can edit details or remove " & Topic.selectedContactData.FirstName & " from your emergency contacts."
+
+ - kind: SendActivity
+ id: update_context_msg
+ activity: "{Topic.updateContextText}"
+
- kind: AdaptiveCardPrompt
id: emergency_contact_form
displayName: Emergency contact form
@@ -340,292 +429,424 @@ beginDialog:
={
type: "AdaptiveCard",
'$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
- version: "1.3",
+ version: "1.5",
body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
{
type: "TextBlock",
- text: If(Topic.isUpdateMode, "Update Emergency Contact", "Add Emergency Contact"),
+ text: If(Topic.isUpdateMode, "Update emergency contact", "Add emergency contact"),
weight: "Bolder",
size: "Medium",
wrap: true,
- color: "Default"
+ spacing: "Medium"
},
{
type: "TextBlock",
- text: If(Topic.isUpdateMode, "Update the details for " & Topic.selectedContactData.DisplayName & ".", "Please provide the details for your emergency contact."),
- wrap: true
+ text: "Fields marked with * are required.",
+ wrap: true,
+ size: "Small",
+ spacing: "Small"
},
{
- type: "Input.Text",
- id: "firstName",
- label: "First Name",
- placeholder: "Enter first name",
- isRequired: true,
- errorMessage: "First name is required.",
- maxLength: 100,
- value: If(Topic.isUpdateMode, Topic.selectedContactData.FirstName, "")
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.Text",
+ id: "firstName",
+ label: "First name",
+ placeholder: "Enter first name",
+ isRequired: true,
+ errorMessage: "First name is required.",
+ maxLength: 100,
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.FirstName, "")
+ }
+ ]
+ },
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.Text",
+ id: "lastName",
+ label: "Last name",
+ placeholder: "Enter last name",
+ isRequired: true,
+ errorMessage: "Last name is required.",
+ maxLength: 100,
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.LastName, "")
+ }
+ ]
+ }
+ ]
},
{
- type: "Input.Text",
- id: "lastName",
- label: "Last Name",
- placeholder: "Enter last name",
- isRequired: true,
- errorMessage: "Last name is required.",
- maxLength: 100,
- value: If(Topic.isUpdateMode, Topic.selectedContactData.LastName, "")
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.ChoiceSet",
+ id: "priority",
+ label: "Priority (only applies if not primary)",
+ style: "compact",
+ isRequired: true,
+ errorMessage: "Please select a priority.",
+ choices: [
+ { title: "2 - High", value: "2" },
+ { title: "3", value: "3" },
+ { title: "4", value: "4" },
+ { title: "5 - Medium", value: "5" },
+ { title: "6", value: "6" },
+ { title: "7", value: "7" },
+ { title: "8", value: "8" },
+ { title: "9", value: "9" },
+ { title: "10 - Low", value: "10" }
+ ],
+ value: If(Topic.isUpdateMode, If(Value(Topic.selectedContactData.Priority) > 1, Topic.selectedContactData.Priority, "2"), "2")
+ }
+ ]
+ },
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.ChoiceSet",
+ id: "relationshipType",
+ label: "Relationship",
+ style: "compact",
+ isRequired: true,
+ errorMessage: "Please select a relationship type.",
+ choices: ForAll(Global.RelatedPersonRelationshipLookupTable, { title: ThisRecord.Referenced_Object_Descriptor, value: ThisRecord.ID }),
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.RelationshipTypeID, First(Global.RelatedPersonRelationshipLookupTable).ID)
+ }
+ ]
+ }
+ ]
},
{
type: "Input.Toggle",
id: "isPrimaryContact",
- title: "Set as Primary Emergency Contact",
+ title: "Set as primary emergency contact",
value: If(Topic.isUpdateMode, If(Topic.selectedContactData.IsPrimary = "true" || Topic.selectedContactData.IsPrimary = "1", "true", "false"), "false"),
valueOn: "true",
valueOff: "false"
},
- {
- type: "Input.ChoiceSet",
- id: "priority",
- label: "Priority (only applies if not primary)",
- style: "compact",
- isRequired: true,
- errorMessage: "Please select a priority.",
- choices: [
- { title: "2 - High", value: "2" },
- { title: "3", value: "3" },
- { title: "4", value: "4" },
- { title: "5 - Medium", value: "5" },
- { title: "6", value: "6" },
- { title: "7", value: "7" },
- { title: "8", value: "8" },
- { title: "9", value: "9" },
- { title: "10 - Low", value: "10" }
- ],
- value: If(Topic.isUpdateMode, If(Value(Topic.selectedContactData.Priority) > 1, Topic.selectedContactData.Priority, "2"), "2")
- },
- {
- type: "Input.ChoiceSet",
- id: "relationshipType",
- label: "Relationship",
- style: "compact",
- isRequired: true,
- errorMessage: "Please select a relationship type.",
- choices: ForAll(Global.RelatedPersonRelationshipLookupTable, { title: ThisRecord.Referenced_Object_Descriptor, value: ThisRecord.ID }),
- value: If(Topic.isUpdateMode, Topic.selectedContactData.RelationshipTypeID, First(Global.RelatedPersonRelationshipLookupTable).ID)
- },
- {
- type: "Input.ChoiceSet",
- id: "phoneCountryCode",
- label: "Phone Country Code",
- style: "compact",
- isRequired: true,
- errorMessage: "Please select a country code.",
- choices: ForAll(Global.CountryCodeLookupTable, { title: ThisRecord.Referenced_Object_Descriptor, value: ThisRecord.ID }),
- value: If(Topic.isUpdateMode, LookUp(Global.CountryCodeLookupTable, Last(Split(ID, "_")).Value = Topic.selectedContactData.PhoneCountryCode).ID, First(Global.CountryCodeLookupTable).ID)
- },
- {
- type: "Input.Text",
- id: "phoneNumber",
- label: "Phone Number",
- placeholder: "Enter phone number (without country code)",
- isRequired: true,
- errorMessage: "Phone number is required.",
- maxLength: 20,
- value: If(Topic.isUpdateMode, Topic.selectedContactData.PhoneNumber, "")
- },
{
type: "Input.ChoiceSet",
id: "phoneDeviceType",
- label: "Phone Type",
+ label: "Phone type",
style: "compact",
isRequired: true,
errorMessage: "Please select a phone type.",
+ separator: true,
choices: [
{ title: "Mobile", value: "Mobile" },
{ title: "Home", value: "Home" },
{ title: "Work", value: "Work" }
],
- value: "Mobile"
+ value: "Mobile",
+ spacing: "Medium"
+ },
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.ChoiceSet",
+ id: "phoneCountryCode",
+ label: "Phone country code",
+ style: "compact",
+ isRequired: true,
+ errorMessage: "Please select a country code.",
+ choices: ForAll(Global.CountryCodeLookupTable, { title: ThisRecord.Referenced_Object_Descriptor, value: ThisRecord.ID }),
+ value: If(Topic.isUpdateMode, LookUp(Global.CountryCodeLookupTable, Last(Split(ID, "_")).Value = Topic.selectedContactData.PhoneCountryCode).ID, First(Global.CountryCodeLookupTable).ID)
+ }
+ ]
+ },
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.Text",
+ id: "phoneNumber",
+ label: "Phone number",
+ placeholder: "Enter phone number",
+ isRequired: true,
+ errorMessage: "Phone number is required.",
+ maxLength: 20,
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.PhoneNumber, "")
+ }
+ ]
+ }
+ ]
},
{
type: "Input.Text",
id: "addressLine1",
- label: "Address Line 1",
+ label: "Address line 1",
placeholder: "Enter street address",
isRequired: true,
errorMessage: "Address is required.",
maxLength: 200,
- value: If(Topic.isUpdateMode, Topic.selectedContactData.AddressLine1, "")
- },
- {
- type: "Input.Text",
- id: "city",
- label: "City",
- placeholder: "Enter city",
- isRequired: true,
- errorMessage: "City is required.",
- maxLength: 100,
- value: If(Topic.isUpdateMode, Topic.selectedContactData.City, "")
- },
- {
- type: "Input.ChoiceSet",
- id: "stateProvince",
- label: "State/Province",
- style: "compact",
- isRequired: true,
- errorMessage: "Please select a state/province.",
- choices: [
- { title: "-- USA --", value: "_USA_HEADER" },
- { title: "Alabama", value: "USA-AL" },
- { title: "Alaska", value: "USA-AK" },
- { title: "Arizona", value: "USA-AZ" },
- { title: "Arkansas", value: "USA-AR" },
- { title: "California", value: "USA-CA" },
- { title: "Colorado", value: "USA-CO" },
- { title: "Connecticut", value: "USA-CT" },
- { title: "Delaware", value: "USA-DE" },
- { title: "Florida", value: "USA-FL" },
- { title: "Georgia", value: "USA-GA" },
- { title: "Hawaii", value: "USA-HI" },
- { title: "Idaho", value: "USA-ID" },
- { title: "Illinois", value: "USA-IL" },
- { title: "Indiana", value: "USA-IN" },
- { title: "Iowa", value: "USA-IA" },
- { title: "Kansas", value: "USA-KS" },
- { title: "Kentucky", value: "USA-KY" },
- { title: "Louisiana", value: "USA-LA" },
- { title: "Maine", value: "USA-ME" },
- { title: "Maryland", value: "USA-MD" },
- { title: "Massachusetts", value: "USA-MA" },
- { title: "Michigan", value: "USA-MI" },
- { title: "Minnesota", value: "USA-MN" },
- { title: "Mississippi", value: "USA-MS" },
- { title: "Missouri", value: "USA-MO" },
- { title: "Montana", value: "USA-MT" },
- { title: "Nebraska", value: "USA-NE" },
- { title: "Nevada", value: "USA-NV" },
- { title: "New Hampshire", value: "USA-NH" },
- { title: "New Jersey", value: "USA-NJ" },
- { title: "New Mexico", value: "USA-NM" },
- { title: "New York", value: "USA-NY" },
- { title: "North Carolina", value: "USA-NC" },
- { title: "North Dakota", value: "USA-ND" },
- { title: "Ohio", value: "USA-OH" },
- { title: "Oklahoma", value: "USA-OK" },
- { title: "Oregon", value: "USA-OR" },
- { title: "Pennsylvania", value: "USA-PA" },
- { title: "Rhode Island", value: "USA-RI" },
- { title: "South Carolina", value: "USA-SC" },
- { title: "South Dakota", value: "USA-SD" },
- { title: "Tennessee", value: "USA-TN" },
- { title: "Texas", value: "USA-TX" },
- { title: "Utah", value: "USA-UT" },
- { title: "Vermont", value: "USA-VT" },
- { title: "Virginia", value: "USA-VA" },
- { title: "Washington", value: "USA-WA" },
- { title: "West Virginia", value: "USA-WV" },
- { title: "Wisconsin", value: "USA-WI" },
- { title: "Wyoming", value: "USA-WY" },
- { title: "District of Columbia", value: "USA-DC" },
- { title: "-- Canada --", value: "_CAN_HEADER" },
- { title: "Alberta", value: "CAN-AB" },
- { title: "British Columbia", value: "CAN-BC" },
- { title: "Manitoba", value: "CAN-MB" },
- { title: "New Brunswick", value: "CAN-NB" },
- { title: "Newfoundland and Labrador", value: "CAN-NL" },
- { title: "Nova Scotia", value: "CAN-NS" },
- { title: "Ontario", value: "CAN-ON" },
- { title: "Prince Edward Island", value: "CAN-PE" },
- { title: "Quebec", value: "CAN-QC" },
- { title: "Saskatchewan", value: "CAN-SK" },
- { title: "-- United Kingdom --", value: "_GBR_HEADER" },
- { title: "England", value: "GBR-ENG" },
- { title: "Scotland", value: "GBR-SCT" },
- { title: "Wales", value: "GBR-WLS" },
- { title: "Northern Ireland", value: "GBR-NIR" },
- { title: "-- India --", value: "_IND_HEADER" },
- { title: "Andhra Pradesh", value: "IND-AP" },
- { title: "Delhi", value: "IND-DL" },
- { title: "Gujarat", value: "IND-GJ" },
- { title: "Haryana", value: "IND-HR" },
- { title: "Karnataka", value: "IND-KA" },
- { title: "Kerala", value: "IND-KL" },
- { title: "Madhya Pradesh", value: "IND-MP" },
- { title: "Maharashtra", value: "IND-MH" },
- { title: "Punjab", value: "IND-PB" },
- { title: "Rajasthan", value: "IND-RJ" },
- { title: "Tamil Nadu", value: "IND-TN" },
- { title: "Telangana", value: "IND-TG" },
- { title: "Uttar Pradesh", value: "IND-UP" },
- { title: "West Bengal", value: "IND-WB" },
- { title: "-- Australia --", value: "_AUS_HEADER" },
- { title: "Australian Capital Territory", value: "AUS-ACT" },
- { title: "New South Wales", value: "AUS-NSW" },
- { title: "Northern Territory", value: "AUS-NT" },
- { title: "Queensland", value: "AUS-QLD" },
- { title: "South Australia", value: "AUS-SA" },
- { title: "Tasmania", value: "AUS-TAS" },
- { title: "Victoria", value: "AUS-VIC" },
- { title: "Western Australia", value: "AUS-WA" },
- { title: "-- Germany --", value: "_DEU_HEADER" },
- { title: "Bavaria", value: "DEU-BY" },
- { title: "Berlin", value: "DEU-BE" },
- { title: "Hamburg", value: "DEU-HH" },
- { title: "Hesse", value: "DEU-HE" },
- { title: "North Rhine-Westphalia", value: "DEU-NW" },
- { title: "-- France --", value: "_FRA_HEADER" },
- { title: "Île-de-France", value: "FRA-IDF" },
- { title: "Provence-Alpes-Côte d'Azur", value: "FRA-PAC" },
- { title: "Auvergne-Rhône-Alpes", value: "FRA-ARA" }
- ],
- value: If(Topic.isUpdateMode, Topic.selectedContactData.StateProvince, "USA-WA")
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.AddressLine1, ""),
+ separator: true,
+ spacing: "Medium"
},
{
- type: "Input.Text",
- id: "postalCode",
- label: "Postal Code",
- placeholder: "Enter postal code",
- isRequired: true,
- errorMessage: "Postal code is required.",
- maxLength: 20,
- value: If(Topic.isUpdateMode, Topic.selectedContactData.PostalCode, "")
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.Text",
+ id: "city",
+ label: "City",
+ placeholder: "Enter city",
+ isRequired: true,
+ errorMessage: "City is required.",
+ maxLength: 100,
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.City, "")
+ }
+ ]
+ },
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.ChoiceSet",
+ id: "stateProvince",
+ label: "State/Province",
+ style: "compact",
+ isRequired: true,
+ errorMessage: "Please select a state/province.",
+ choices: [
+ { title: "-- USA --", value: "_USA_HEADER" },
+ { title: "Alabama", value: "USA-AL" },
+ { title: "Alaska", value: "USA-AK" },
+ { title: "Arizona", value: "USA-AZ" },
+ { title: "Arkansas", value: "USA-AR" },
+ { title: "California", value: "USA-CA" },
+ { title: "Colorado", value: "USA-CO" },
+ { title: "Connecticut", value: "USA-CT" },
+ { title: "Delaware", value: "USA-DE" },
+ { title: "Florida", value: "USA-FL" },
+ { title: "Georgia", value: "USA-GA" },
+ { title: "Hawaii", value: "USA-HI" },
+ { title: "Idaho", value: "USA-ID" },
+ { title: "Illinois", value: "USA-IL" },
+ { title: "Indiana", value: "USA-IN" },
+ { title: "Iowa", value: "USA-IA" },
+ { title: "Kansas", value: "USA-KS" },
+ { title: "Kentucky", value: "USA-KY" },
+ { title: "Louisiana", value: "USA-LA" },
+ { title: "Maine", value: "USA-ME" },
+ { title: "Maryland", value: "USA-MD" },
+ { title: "Massachusetts", value: "USA-MA" },
+ { title: "Michigan", value: "USA-MI" },
+ { title: "Minnesota", value: "USA-MN" },
+ { title: "Mississippi", value: "USA-MS" },
+ { title: "Missouri", value: "USA-MO" },
+ { title: "Montana", value: "USA-MT" },
+ { title: "Nebraska", value: "USA-NE" },
+ { title: "Nevada", value: "USA-NV" },
+ { title: "New Hampshire", value: "USA-NH" },
+ { title: "New Jersey", value: "USA-NJ" },
+ { title: "New Mexico", value: "USA-NM" },
+ { title: "New York", value: "USA-NY" },
+ { title: "North Carolina", value: "USA-NC" },
+ { title: "North Dakota", value: "USA-ND" },
+ { title: "Ohio", value: "USA-OH" },
+ { title: "Oklahoma", value: "USA-OK" },
+ { title: "Oregon", value: "USA-OR" },
+ { title: "Pennsylvania", value: "USA-PA" },
+ { title: "Rhode Island", value: "USA-RI" },
+ { title: "South Carolina", value: "USA-SC" },
+ { title: "South Dakota", value: "USA-SD" },
+ { title: "Tennessee", value: "USA-TN" },
+ { title: "Texas", value: "USA-TX" },
+ { title: "Utah", value: "USA-UT" },
+ { title: "Vermont", value: "USA-VT" },
+ { title: "Virginia", value: "USA-VA" },
+ { title: "Washington", value: "USA-WA" },
+ { title: "West Virginia", value: "USA-WV" },
+ { title: "Wisconsin", value: "USA-WI" },
+ { title: "Wyoming", value: "USA-WY" },
+ { title: "District of Columbia", value: "USA-DC" },
+ { title: "-- Canada --", value: "_CAN_HEADER" },
+ { title: "Alberta", value: "CAN-AB" },
+ { title: "British Columbia", value: "CAN-BC" },
+ { title: "Manitoba", value: "CAN-MB" },
+ { title: "New Brunswick", value: "CAN-NB" },
+ { title: "Newfoundland and Labrador", value: "CAN-NL" },
+ { title: "Nova Scotia", value: "CAN-NS" },
+ { title: "Ontario", value: "CAN-ON" },
+ { title: "Prince Edward Island", value: "CAN-PE" },
+ { title: "Quebec", value: "CAN-QC" },
+ { title: "Saskatchewan", value: "CAN-SK" },
+ { title: "-- United Kingdom --", value: "_GBR_HEADER" },
+ { title: "England", value: "GBR-ENG" },
+ { title: "Scotland", value: "GBR-SCT" },
+ { title: "Wales", value: "GBR-WLS" },
+ { title: "Northern Ireland", value: "GBR-NIR" },
+ { title: "-- India --", value: "_IND_HEADER" },
+ { title: "Andhra Pradesh", value: "IND-AP" },
+ { title: "Delhi", value: "IND-DL" },
+ { title: "Gujarat", value: "IND-GJ" },
+ { title: "Haryana", value: "IND-HR" },
+ { title: "Karnataka", value: "IND-KA" },
+ { title: "Kerala", value: "IND-KL" },
+ { title: "Madhya Pradesh", value: "IND-MP" },
+ { title: "Maharashtra", value: "IND-MH" },
+ { title: "Punjab", value: "IND-PB" },
+ { title: "Rajasthan", value: "IND-RJ" },
+ { title: "Tamil Nadu", value: "IND-TN" },
+ { title: "Telangana", value: "IND-TG" },
+ { title: "Uttar Pradesh", value: "IND-UP" },
+ { title: "West Bengal", value: "IND-WB" },
+ { title: "-- Australia --", value: "_AUS_HEADER" },
+ { title: "Australian Capital Territory", value: "AUS-ACT" },
+ { title: "New South Wales", value: "AUS-NSW" },
+ { title: "Northern Territory", value: "AUS-NT" },
+ { title: "Queensland", value: "AUS-QLD" },
+ { title: "South Australia", value: "AUS-SA" },
+ { title: "Tasmania", value: "AUS-TAS" },
+ { title: "Victoria", value: "AUS-VIC" },
+ { title: "Western Australia", value: "AUS-WA" },
+ { title: "-- Germany --", value: "_DEU_HEADER" },
+ { title: "Bavaria", value: "DEU-BY" },
+ { title: "Berlin", value: "DEU-BE" },
+ { title: "Hamburg", value: "DEU-HH" },
+ { title: "Hesse", value: "DEU-HE" },
+ { title: "North Rhine-Westphalia", value: "DEU-NW" },
+ { title: "-- France --", value: "_FRA_HEADER" },
+ { title: "Île-de-France", value: "FRA-IDF" },
+ { title: "Provence-Alpes-Côte d'Azur", value: "FRA-PAC" },
+ { title: "Auvergne-Rhône-Alpes", value: "FRA-ARA" }
+ ],
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.StateProvince, "USA-WA")
+ }
+ ]
+ }
+ ]
},
{
- type: "Input.ChoiceSet",
- id: "countryCode",
- label: "Country",
- style: "compact",
- isRequired: true,
- errorMessage: "Please select a country.",
- choices: [
- { title: "United States", value: "USA" },
- { title: "Canada", value: "CAN" },
- { title: "United Kingdom", value: "GBR" },
- { title: "India", value: "IND" },
- { title: "Australia", value: "AUS" },
- { title: "Germany", value: "DEU" },
- { title: "France", value: "FRA" },
- { title: "Japan", value: "JPN" },
- { title: "China", value: "CHN" },
- { title: "Brazil", value: "BRA" },
- { title: "Mexico", value: "MEX" },
- { title: "Italy", value: "ITA" },
- { title: "Spain", value: "ESP" },
- { title: "Netherlands", value: "NLD" },
- { title: "Singapore", value: "SGP" },
- { title: "Ireland", value: "IRL" },
- { title: "Israel", value: "ISR" },
- { title: "South Korea", value: "KOR" },
- { title: "Switzerland", value: "CHE" },
- { title: "Sweden", value: "SWE" }
- ],
- value: If(Topic.isUpdateMode, Topic.selectedContactData.CountryCode, "USA")
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.Text",
+ id: "postalCode",
+ label: "Postal code",
+ placeholder: "Enter postal code",
+ isRequired: true,
+ errorMessage: "Postal code is required.",
+ maxLength: 20,
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.PostalCode, "")
+ }
+ ]
+ },
+ {
+ type: "Column",
+ width: "stretch",
+ items: [
+ {
+ type: "Input.ChoiceSet",
+ id: "countryCode",
+ label: "Country",
+ style: "compact",
+ isRequired: true,
+ errorMessage: "Please select a country.",
+ choices: [
+ { title: "United States", value: "USA" },
+ { title: "Canada", value: "CAN" },
+ { title: "United Kingdom", value: "GBR" },
+ { title: "India", value: "IND" },
+ { title: "Australia", value: "AUS" },
+ { title: "Germany", value: "DEU" },
+ { title: "France", value: "FRA" },
+ { title: "Japan", value: "JPN" },
+ { title: "China", value: "CHN" },
+ { title: "Brazil", value: "BRA" },
+ { title: "Mexico", value: "MEX" },
+ { title: "Italy", value: "ITA" },
+ { title: "Spain", value: "ESP" },
+ { title: "Netherlands", value: "NLD" },
+ { title: "Singapore", value: "SGP" },
+ { title: "Ireland", value: "IRL" },
+ { title: "Israel", value: "ISR" },
+ { title: "South Korea", value: "KOR" },
+ { title: "Switzerland", value: "CHE" },
+ { title: "Sweden", value: "SWE" }
+ ],
+ value: If(Topic.isUpdateMode, Topic.selectedContactData.CountryCode, "USA")
+ }
+ ]
+ }
+ ]
}
],
- actions: [
- { type: "Action.Submit", title: If(Topic.isUpdateMode, "Update", "Submit") },
- { type: "Action.Submit", title: "Cancel", associatedInputs: "none" }
- ]
+ actions: If(Topic.isUpdateMode,
+ [
+ { type: "Action.Submit", title: "Submit changes", id: "Submit", data: { actionSubmitId: "Submit" } },
+ { type: "Action.Submit", title: "Delete contact", id: "Delete", data: { actionSubmitId: "Delete" }, associatedInputs: "none" },
+ { type: "Action.Submit", title: "Cancel", id: "Cancel", data: { actionSubmitId: "Cancel" }, associatedInputs: "none" }
+ ],
+ [
+ { type: "Action.Submit", title: "Submit", id: "Submit", data: { actionSubmitId: "Submit" } },
+ { type: "Action.Submit", title: "Cancel", id: "Cancel", data: { actionSubmitId: "Cancel" }, associatedInputs: "none" }
+ ]
+ )
}
output:
binding:
@@ -674,72 +895,431 @@ beginDialog:
- kind: CancelAllDialogs
id: form_cancel_all
+ # Handle delete action - show confirmation
- kind: ConditionGroup
- id: submit_to_workday
+ id: handle_delete_action
conditions:
- - id: is_update_submit
- condition: =Topic.isUpdateMode = true
- displayName: Submit update to Workday
+ - id: delete_requested
+ condition: =Topic.formActionId = "Delete"
+ displayName: User wants to delete contact
actions:
- - kind: BeginDialog
- id: execute_update
- displayName: Execute Workday Update
- input:
- binding:
- parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Emergency_Contact_WID}"",""value"":""" & Topic.selectedContactWID & """},{""key"":""{Effective_Date}"",""value"":"""& Text(Today(), "yyyy-MM-dd") &"""},{""key"":""{First_Name}"",""value"":""" & Topic.firstName & """},{""key"":""{Last_Name}"",""value"":""" & Topic.lastName & """},{""key"":""{Primary}"",""value"":""" & Topic.isPrimaryContact & """},{""key"":""{Priority}"",""value"":""" & If(Topic.isPrimaryContact = "true", "1", Topic.priority) & """},{""key"":""{Relationship_Type}"",""value"":""" & Topic.relationshipType & """},{""key"":""{Phone_Number}"",""value"":""" & Topic.phoneNumber & """},{""key"":""{Phone_Device_Type}"",""value"":""" & Topic.phoneDeviceType & """},{""key"":""{Phone_Country_Code}"",""value"":""" & Last(Split(Topic.phoneCountryCode, "_")).Value & """},{""key"":""{Address_Line_1}"",""value"":""" & Topic.addressLine1 & """},{""key"":""{City}"",""value"":""" & Topic.city & """},{""key"":""{State_Province}"",""value"":""" & Topic.stateProvince & """},{""key"":""{Postal_Code}"",""value"":""" & Topic.postalCode & """},{""key"":""{Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Address_Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Comment}"",""value"":""Updating emergency contact""}]}"
- scenarioName: msdyn_UpdateEmergencyContact
+ # Check if contact is primary - don't allow delete
+ - kind: ConditionGroup
+ id: check_primary_delete
+ conditions:
+ - id: is_primary_contact
+ condition: =Topic.selectedContactData.IsPrimary = "true" || Topic.selectedContactData.IsPrimary = "1"
+ displayName: Cannot delete primary contact
+ actions:
+ - kind: SendActivity
+ id: cannot_delete_primary_msg
+ activity: You cannot delete your primary emergency contact. Please designate another contact as primary first, then you can remove this one.
- dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
- output:
- binding:
- errorResponse: Topic.errorResponse
- isSuccess: Topic.isSuccess
- workdayResponse: Topic.workdayResponse
+ - kind: CancelAllDialogs
+ id: cancel_primary_delete
- elseActions:
- - kind: BeginDialog
- id: execute_add
- displayName: Execute Workday Add
- input:
- binding:
- parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Effective_Date}"",""value"":"""& Text(Today(), "yyyy-MM-dd") &"""},{""key"":""{First_Name}"",""value"":""" & Topic.firstName & """},{""key"":""{Last_Name}"",""value"":""" & Topic.lastName & """},{""key"":""{Primary}"",""value"":""" & Topic.isPrimaryContact & """},{""key"":""{Priority}"",""value"":""" & If(Topic.isPrimaryContact = "true", "1", Topic.priority) & """},{""key"":""{Relationship_Type}"",""value"":""" & Topic.relationshipType & """},{""key"":""{Phone_Number}"",""value"":""" & Topic.phoneNumber & """},{""key"":""{Phone_Device_Type}"",""value"":""" & Topic.phoneDeviceType & """},{""key"":""{Phone_Country_Code}"",""value"":""" & Last(Split(Topic.phoneCountryCode, "_")).Value & """},{""key"":""{Address_Line_1}"",""value"":""" & Topic.addressLine1 & """},{""key"":""{City}"",""value"":""" & Topic.city & """},{""key"":""{State_Province}"",""value"":""" & Topic.stateProvince & """},{""key"":""{Postal_Code}"",""value"":""" & Topic.postalCode & """},{""key"":""{Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Address_Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Comment}"",""value"":""Adding emergency contact""}]}"
- scenarioName: msdyn_HRWorkdayHCMEmployeeAddEmergencyContact
-
- dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
- output:
- binding:
- errorResponse: Topic.errorResponse
- isSuccess: Topic.isSuccess
- workdayResponse: Topic.workdayResponse
+ elseActions:
+ # Not primary - proceed with delete confirmation
+ - kind: SetVariable
+ id: set_delete_confirm_text
+ variable: Topic.deleteConfirmText
+ value: ="Are you sure you want to delete this emergency contact?"
+
+ - kind: SendActivity
+ id: delete_confirm_text_msg
+ activity: "{Topic.deleteConfirmText}"
+
+ - kind: AdaptiveCardPrompt
+ id: confirm_delete_card
+ displayName: Confirm delete
+ card: |-
+ ={
+ type: "AdaptiveCard",
+ '$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
+ version: "1.5",
+ body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
+ {
+ type: "TextBlock",
+ text: "Confirm deletion",
+ weight: "Bolder",
+ size: "Medium",
+ wrap: true,
+ spacing: "Medium"
+ },
+ {
+ type: "FactSet",
+ spacing: "Medium",
+ facts: [
+ { title: "Name", value: Topic.selectedContactData.FirstName & " " & Topic.selectedContactData.LastName },
+ { title: "Priority", value: LookUp([{v:"2",t:"2 - High"},{v:"3",t:"3"},{v:"4",t:"4"},{v:"5",t:"5 - Medium"},{v:"6",t:"6"},{v:"7",t:"7"},{v:"8",t:"8"},{v:"9",t:"9"},{v:"10",t:"10 - Low"}], v = Topic.selectedContactData.Priority).t },
+ { title: "Relationship", value: Topic.selectedContactData.RelationshipType },
+ { title: "Phone", value: Topic.selectedContactData.Phone },
+ { title: "Address", value: Topic.selectedContactData.Address }
+ ]
+ }
+ ],
+ actions: [
+ { type: "Action.Submit", title: "Yes, delete", id: "Yes", data: { actionSubmitId: "Yes" } },
+ { type: "Action.Submit", title: "Cancel", id: "No", data: { actionSubmitId: "No" } }
+ ]
+ }
+ output:
+ binding:
+ actionSubmitId: Topic.confirmDeleteAction
+ outputType:
+ properties:
+ actionSubmitId: String
+
+ - kind: ConditionGroup
+ id: check_delete_confirmation
+ conditions:
+ - id: confirmed_delete
+ condition: =Topic.confirmDeleteAction = "Yes"
+ displayName: User confirmed delete
+ actions:
+ - kind: BeginDialog
+ id: execute_delete
+ displayName: Execute Workday Delete
+ input:
+ binding:
+ parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Emergency_Contact_WID}"",""value"":""" & Topic.selectedContactWID & """},{""key"":""{Priority}"",""value"":""" & Topic.selectedContactData.Priority & """},{""key"":""{Relationship_Type}"",""value"":""" & Topic.selectedContactData.RelationshipTypeID & """},{""key"":""{Comment}"",""value"":""Removing emergency contact via Copilot""}]}"
+ scenarioName: msdyn_DeleteEmergencyContact
+
+ dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
+ output:
+ binding:
+ errorResponse: Topic.errorResponse
+ isSuccess: Topic.isSuccess
+ workdayResponse: Topic.workdayResponse
+
+ - kind: ConditionGroup
+ id: report_delete_result
+ conditions:
+ - id: delete_failed
+ condition: =Topic.isSuccess = false
+ actions:
+ # Parse error message for display
+ - kind: SetVariable
+ id: set_delete_error_raw
+ variable: Topic.deleteErrorRaw
+ value: =Topic.errorResponse
+
+ - kind: SetVariable
+ id: parse_delete_error
+ variable: Topic.deleteErrorParsed
+ value: =IfError(Text(ParseJSON(Topic.deleteErrorRaw).error.message), IfError(Text(ParseJSON(Topic.deleteErrorRaw).message), Topic.deleteErrorRaw))
+
+ - kind: SetVariable
+ id: set_delete_error_display
+ variable: Topic.deleteErrorDisplay
+ value: =If(IsBlank(Topic.deleteErrorParsed), "An unknown error occurred.", Topic.deleteErrorParsed)
+
+ - kind: SendActivity
+ id: delete_failure_msg
+ activity: |-
+ An error occurred and the emergency contact was not deleted.
+
+ **Error details:** {Topic.deleteErrorDisplay}
+
+ Please try again or contact support.
+
+ - kind: CancelAllDialogs
+ id: end_on_delete_failure
+
+ elseActions:
+ - kind: SendActivity
+ id: delete_success_msg
+ activity:
+ attachments:
+ - kind: AdaptiveCardTemplate
+ cardContent: |-
+ ={
+ type: "AdaptiveCard",
+ '$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
+ version: "1.5",
+ body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
+ {
+ type: "TextBlock",
+ text: "✅ Emergency contact deleted",
+ weight: "Bolder",
+ size: "Medium",
+ wrap: true,
+ spacing: "Medium"
+ },
+ {
+ type: "FactSet",
+ spacing: "Medium",
+ facts: [
+ { title: "Name", value: Topic.selectedContactData.FirstName & " " & Topic.selectedContactData.LastName },
+ { title: "Priority", value: LookUp([{v:"2",t:"2 - High"},{v:"3",t:"3"},{v:"4",t:"4"},{v:"5",t:"5 - Medium"},{v:"6",t:"6"},{v:"7",t:"7"},{v:"8",t:"8"},{v:"9",t:"9"},{v:"10",t:"10 - Low"}], v = Topic.selectedContactData.Priority).t },
+ { title: "Relationship", value: Topic.selectedContactData.RelationshipType },
+ { title: "Phone", value: Topic.selectedContactData.Phone },
+ { title: "Address", value: Topic.selectedContactData.Address }
+ ]
+ }
+ ]
+ }
+
+ - kind: CancelAllDialogs
+ id: end_delete_dialogs
+
+ elseActions:
+ - kind: SendActivity
+ id: delete_cancelled_msg
+ activity: Delete cancelled. Is there anything else I can help you with?
+
+ - kind: CancelAllDialogs
+ id: cancel_delete_dialogs
+
+ # Only process submit action (not cancel or delete)
- kind: ConditionGroup
- id: report_result
+ id: check_submit_action
conditions:
- - id: failed
- condition: =Topic.isSuccess = false
+ - id: is_submit_action
+ condition: =Topic.formActionId = "Submit"
+ displayName: User submitted the form
actions:
- - kind: SendActivity
- id: failure_msg
- activity: ={If(Topic.isUpdateMode, "An error occurred and your emergency contact was not updated.", "An error occurred and your emergency contact was not added.") & " Please try again or contact support."}
+ - kind: ConditionGroup
+ id: submit_to_workday
+ conditions:
+ - id: is_update_submit
+ condition: =Topic.isUpdateMode = true
+ displayName: Submit update to Workday
+ actions:
+ - kind: BeginDialog
+ id: execute_update
+ displayName: Execute Workday Update
+ input:
+ binding:
+ parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Emergency_Contact_WID}"",""value"":""" & Topic.selectedContactWID & """},{""key"":""{Effective_Date}"",""value"":"""& Text(Today(), "yyyy-MM-dd") &"""},{""key"":""{First_Name}"",""value"":""" & Topic.firstName & """},{""key"":""{Last_Name}"",""value"":""" & Topic.lastName & """},{""key"":""{Primary}"",""value"":""" & Topic.isPrimaryContact & """},{""key"":""{Priority}"",""value"":""" & If(Topic.isPrimaryContact = "true", "1", Topic.priority) & """},{""key"":""{Relationship_Type}"",""value"":""" & Topic.relationshipType & """},{""key"":""{Phone_Number}"",""value"":""" & Topic.phoneNumber & """},{""key"":""{Phone_Device_Type}"",""value"":""" & Topic.phoneDeviceType & """},{""key"":""{Phone_Country_Code}"",""value"":""" & Last(Split(Topic.phoneCountryCode, "_")).Value & """},{""key"":""{Address_Line_1}"",""value"":""" & Topic.addressLine1 & """},{""key"":""{City}"",""value"":""" & Topic.city & """},{""key"":""{State_Province}"",""value"":""" & Topic.stateProvince & """},{""key"":""{Postal_Code}"",""value"":""" & Topic.postalCode & """},{""key"":""{Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Address_Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Comment}"",""value"":""Updating emergency contact""}]}"
+ scenarioName: msdyn_UpdateEmergencyContact
+
+ dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
+ output:
+ binding:
+ errorResponse: Topic.errorResponse
+ isSuccess: Topic.isSuccess
+ workdayResponse: Topic.workdayResponse
+
+ elseActions:
+ - kind: BeginDialog
+ id: execute_add
+ displayName: Execute Workday Add
+ input:
+ binding:
+ parameters: ="{""params"":[{""key"":""{Employee_ID}"",""value"":""" & Global.ESS_UserContext_Employee_Id & """},{""key"":""{Effective_Date}"",""value"":"""& Text(Today(), "yyyy-MM-dd") &"""},{""key"":""{First_Name}"",""value"":""" & Topic.firstName & """},{""key"":""{Last_Name}"",""value"":""" & Topic.lastName & """},{""key"":""{Primary}"",""value"":""" & Topic.isPrimaryContact & """},{""key"":""{Priority}"",""value"":""" & If(Topic.isPrimaryContact = "true", "1", Topic.priority) & """},{""key"":""{Relationship_Type}"",""value"":""" & Topic.relationshipType & """},{""key"":""{Phone_Number}"",""value"":""" & Topic.phoneNumber & """},{""key"":""{Phone_Device_Type}"",""value"":""" & Topic.phoneDeviceType & """},{""key"":""{Phone_Country_Code}"",""value"":""" & Last(Split(Topic.phoneCountryCode, "_")).Value & """},{""key"":""{Address_Line_1}"",""value"":""" & Topic.addressLine1 & """},{""key"":""{City}"",""value"":""" & Topic.city & """},{""key"":""{State_Province}"",""value"":""" & Topic.stateProvince & """},{""key"":""{Postal_Code}"",""value"":""" & Topic.postalCode & """},{""key"":""{Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Address_Country_Code}"",""value"":""" & Topic.countryCode & """},{""key"":""{Comment}"",""value"":""Adding emergency contact""}]}"
+ scenarioName: msdyn_HRWorkdayHCMEmployeeAddEmergencyContact
+
+ dialog: msdyn_copilotforemployeeselfservicehr.topic.WorkdaySystemGetCommonExecution
+ output:
+ binding:
+ errorResponse: Topic.errorResponse
+ isSuccess: Topic.isSuccess
+ workdayResponse: Topic.workdayResponse
+
+ - kind: ConditionGroup
+ id: report_result
+ conditions:
+ - id: failed
+ condition: =Topic.isSuccess = false
+ actions:
+ # Parse error message for display
+ - kind: SetVariable
+ id: set_submit_error_raw
+ variable: Topic.submitErrorRaw
+ value: =Topic.errorResponse
+
+ - kind: SetVariable
+ id: parse_submit_error
+ variable: Topic.submitErrorParsed
+ value: =IfError(Text(ParseJSON(Topic.submitErrorRaw).error.message), IfError(Text(ParseJSON(Topic.submitErrorRaw).message), Topic.submitErrorRaw))
+
+ - kind: SetVariable
+ id: set_submit_error_display
+ variable: Topic.submitErrorDisplay
+ value: =If(IsBlank(Topic.submitErrorParsed), "An unknown error occurred.", Topic.submitErrorParsed)
+
+ - kind: SetVariable
+ id: set_failure_msg_text
+ variable: Topic.failureMsgText
+ value: =If(Topic.isUpdateMode, "An error occurred and your emergency contact was not updated.", "An error occurred and your emergency contact was not added.")
+
+ - kind: SendActivity
+ id: failure_msg
+ activity: |-
+ {Topic.failureMsgText}
+
+ **Error details:** {Topic.submitErrorDisplay}
+
+ Please try again or contact support.
+
+ - kind: CancelAllDialogs
+ id: end_on_failure
+
+ elseActions:
+ - kind: SetVariable
+ id: set_workday_url
+ variable: Topic.WorkdayUrl
+ value: ="https://impl.workday.com/microsoft_dpt6/d/home.htmld"
+
+ - kind: SetVariable
+ id: set_success_intro_text
+ variable: Topic.successIntroText
+ value: =If(Topic.isUpdateMode, "Great! You've updated your emergency contact.", "Great! You've added a new emergency contact.")
- elseActions:
- - kind: ConditionGroup
- id: success_message_condition
- conditions:
- - id: update_success
- condition: =Topic.isUpdateMode = true
- actions:
- kind: SendActivity
- id: update_success_msg
- activity: Your emergency contact has been successfully updated in Workday.
+ id: success_intro_msg
+ activity: "{Topic.successIntroText}"
- elseActions:
- - kind: SendActivity
- id: add_success_msg
- activity: Your emergency contact has been successfully added to Workday.
+ - kind: SendActivity
+ id: success_card
+ activity:
+ attachments:
+ - kind: AdaptiveCardTemplate
+ cardContent: |-
+ ={
+ type: "AdaptiveCard",
+ '$schema': "http://adaptivecards.io/schemas/adaptive-card.json",
+ version: "1.5",
+ body: [
+ {
+ type: "ColumnSet",
+ columns: [
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "Image",
+ url: Topic.WorkdayIconUrl,
+ style: "RoundedCorners",
+ size: "Small",
+ height: "20px",
+ width: "20px"
+ }
+ ],
+ verticalContentAlignment: "Center"
+ },
+ {
+ type: "Column",
+ width: "auto",
+ items: [
+ {
+ type: "TextBlock",
+ text: "Workday",
+ size: "Small",
+ weight: "Bolder"
+ }
+ ],
+ verticalContentAlignment: "Center",
+ spacing: "Small"
+ }
+ ]
+ },
+ {
+ type: "TextBlock",
+ text: If(Topic.isUpdateMode, "✅ Emergency contact updated", "✅ Emergency contact added"),
+ weight: "Bolder",
+ size: "Medium",
+ wrap: true,
+ spacing: "Medium"
+ },
+ {
+ type: "FactSet",
+ spacing: "Medium",
+ facts: [
+ { title: "Name", value: Topic.firstName & " " & Topic.lastName },
+ { title: "Priority", value: If(Topic.isPrimaryContact = "true", "Primary", LookUp([{v:"2",t:"2 - High"},{v:"3",t:"3"},{v:"4",t:"4"},{v:"5",t:"5 - Medium"},{v:"6",t:"6"},{v:"7",t:"7"},{v:"8",t:"8"},{v:"9",t:"9"},{v:"10",t:"10 - Low"}], v = Topic.priority).t) },
+ { title: "Relationship", value: LookUp(Global.RelatedPersonRelationshipLookupTable, ID = Topic.relationshipType).Referenced_Object_Descriptor },
+ { title: "Phone", value: "+" & Last(Split(Topic.phoneCountryCode, "_")).Value & "-" & Topic.phoneNumber & " (" & Topic.phoneDeviceType & ")" },
+ { title: "Address", value: Topic.addressLine1 & " " & Topic.city & ", " & Topic.countryCode & " " & Topic.postalCode }
+ ]
+ }
+ ]
+ }
+ - kind: CancelAllDialogs
+ id: end_dialogs
+
+ elseActions:
+ # This handles case when formActionId is not "Submit" (fallback for Cancel/Delete that weren't caught)
- kind: CancelAllDialogs
- id: end_dialogs
+ id: end_unexpected_action
+
+inputType:
+ properties:
+ InputAction:
+ displayName: InputAction
+ description: The action the user wants to perform (add, update, manage).
+ type: String
-inputType: {}
outputType: {}
\ No newline at end of file
diff --git a/EmployeeSelfServiceAgent/Workday/ManagerScenarios/WorkdayGetManagerReporteesTimeInPosition/topic.yaml b/EmployeeSelfServiceAgent/Workday/ManagerScenarios/WorkdayGetManagerReporteesTimeInPosition/topic.yaml
index adecac4b..c3b88622 100644
--- a/EmployeeSelfServiceAgent/Workday/ManagerScenarios/WorkdayGetManagerReporteesTimeInPosition/topic.yaml
+++ b/EmployeeSelfServiceAgent/Workday/ManagerScenarios/WorkdayGetManagerReporteesTimeInPosition/topic.yaml
@@ -1,14 +1,21 @@
kind: AdaptiveDialog
modelDescription: |-
- You will respond to requests about time in position for direct reports of the user making the request. There is no information available for anyone who isn't a direct report, and being a direct report means that the individual is not a manager, spouse, sibling, or any other relationship to the requestor, and only means that they report to the requestor. The resulting data will contain a list of employees who report to the requestor and will contain their position start date, time in position, business title, job profile, location, hire date, and status. You must NOT give data if you do not have enough info.
-
-
- Example valid request:
- "What is the time in position of my direct reports?"
- "Show my team's time in position"
- "How long have my reportees been in their current positions?"
-
- Your output **must** be a nested list in markdown language based on the data contained in the {Topic.workdayResponseTableWithTimeInPosition} variable
+ You will respond to requests about time in position for direct reports of the user making the request.
+
+ For info on single direct report's time in position:
+ Heading - "[Report]'s time in position"
+ Verbatim line after heading: "[Report] has been in their current role as a [Position] for [LengthOfService]. I pulled this from Workday, an HR platform your company uses."
+ Sections as headers and bullets within: More about [Direct Report]'s position
+
+ For info on all direct reports time in position: Display in table
+ Heading - "Team roles and time in position"
+ Verbatim line after heading: "Here's a list of your team members and how long they've been in their positions. I pulled this from Workday, an HR platform your company uses."
+ Table columns: Name, Title, Time in Position
+
+ Common Rules (STRICT!):
+ - ALWAYS KEEP LARGE HEADING
+ - Introduction (Relevant) RIGHT AFTER HEADING & ADD SECTION LINE AFTER IT,
+ Invalid: non-direct reports.
beginDialog:
kind: OnRecognizedIntent
id: main