diff --git a/docs/data-sources/user.md b/docs/data-sources/user.md index 850339baf..fa3e65176 100644 --- a/docs/data-sources/user.md +++ b/docs/data-sources/user.md @@ -50,6 +50,7 @@ The following attributes are exported: * `department` - The name for the department in which the user works. * `display_name` - The display name of the user. * `division` - The name of the division in which the user works. +* `employee_hire_date` - The hire date of the user, formatted as an RFC3339 date string (e.g. `2018-01-01T01:02:03Z`). * `employee_id` - The employee identifier assigned to the user by the organisation. * `employee_type` - Captures enterprise worker type. For example, Employee, Contractor, Consultant, or Vendor. * `external_user_state` - For an external user invited to the tenant, this property represents the invited user's invitation status. Possible values are `PendingAcceptance` or `Accepted`. diff --git a/docs/resources/user.md b/docs/resources/user.md index 4c5f6c771..d36a765ee 100644 --- a/docs/resources/user.md +++ b/docs/resources/user.md @@ -42,6 +42,7 @@ The following arguments are supported: * `disable_strong_password` - (Optional) Whether the user is allowed weaker passwords than the default policy to be specified. Defaults to `false`. * `display_name` - (Required) The name to display in the address book for the user. * `division` - (Optional) The name of the division in which the user works. +* `employee_hire_date` - (Optional) The hire date of the user, formatted as an RFC3339 date string (e.g. `2018-01-01T01:02:03Z`). * `employee_id` - (Optional) The employee identifier assigned to the user by the organisation. * `employee_type` - (Optional) Captures enterprise worker type. For example, Employee, Contractor, Consultant, or Vendor. * `fax_number` - (Optional) The fax number of the user. diff --git a/internal/services/users/user_data_source.go b/internal/services/users/user_data_source.go index 6c48fa83f..9022085b2 100644 --- a/internal/services/users/user_data_source.go +++ b/internal/services/users/user_data_source.go @@ -150,6 +150,12 @@ func userDataSource() *pluginsdk.Resource { Computed: true, }, + "employee_hire_date": { + Description: "The hire date of the user, formatted as an RFC3339 date string (e.g. `2018-01-01T01:02:03Z`).", + Type: pluginsdk.TypeString, + Computed: true, + }, + "employee_type": { Description: "Captures enterprise worker type. For example, Employee, Contractor, Consultant, or Vendor.", Type: pluginsdk.TypeString, @@ -452,6 +458,7 @@ func userDataSourceRead(ctx context.Context, d *pluginsdk.ResourceData, meta int "creationType", "department", "displayName", + "employeeHireDate", "employeeId", "employeeOrgData", "employeeType", @@ -509,6 +516,7 @@ func userDataSourceRead(ctx context.Context, d *pluginsdk.ResourceData, meta int tf.Set(d, "creation_type", u.CreationType.GetOrZero()) tf.Set(d, "department", u.Department.GetOrZero()) tf.Set(d, "display_name", u.DisplayName.GetOrZero()) + tf.Set(d, "employee_hire_date", u.EmployeeHireDate.GetOrZero()) tf.Set(d, "employee_id", u.EmployeeId.GetOrZero()) tf.Set(d, "employee_type", u.EmployeeType.GetOrZero()) tf.Set(d, "external_user_state", u.ExternalUserState.GetOrZero()) diff --git a/internal/services/users/user_data_source_test.go b/internal/services/users/user_data_source_test.go index 0c9673599..e27cd48cb 100644 --- a/internal/services/users/user_data_source_test.go +++ b/internal/services/users/user_data_source_test.go @@ -117,6 +117,7 @@ func (UserDataSource) testCheckFunc(data acceptance.TestData) acceptance.TestChe check.That(data.ResourceName).Key("country").HasValue(fmt.Sprintf("acctestUser-%d-Country", data.RandomInteger)), check.That(data.ResourceName).Key("department").HasValue(fmt.Sprintf("acctestUser-%d-Dept", data.RandomInteger)), check.That(data.ResourceName).Key("display_name").HasValue(fmt.Sprintf("acctestUser-%d-DisplayName", data.RandomInteger)), + check.That(data.ResourceName).Key("employee_hire_date").HasValue("2018-01-01T01:02:03Z"), check.That(data.ResourceName).Key("given_name").HasValue(fmt.Sprintf("acctestUser-%d-GivenName", data.RandomInteger)), check.That(data.ResourceName).Key("job_title").HasValue(fmt.Sprintf("acctestUser-%d-Job", data.RandomInteger)), // check.That(data.ResourceName).Key("mail").Exists(), // TODO only set for O365 domains diff --git a/internal/services/users/user_resource.go b/internal/services/users/user_resource.go index 2590be421..c3e6ef0a9 100644 --- a/internal/services/users/user_resource.go +++ b/internal/services/users/user_resource.go @@ -147,6 +147,13 @@ func userResource() *pluginsdk.Resource { Optional: true, }, + "employee_hire_date": { + Description: "The hire date of the user, formatted as an RFC3339 date string (e.g. `2018-01-01T01:02:03Z`).", + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.IsRFC3339Time, + }, + "employee_id": { Description: "The employee identifier assigned to the user by the organisation", Type: pluginsdk.TypeString, @@ -475,6 +482,14 @@ func userResourceCreate(ctx context.Context, d *pluginsdk.ResourceData, meta int properties.OnPremisesImmutableId = nullable.NoZero(v.(string)) } + if v, ok := d.GetOk("employee_hire_date"); ok { + _, err := time.Parse(time.RFC3339, v.(string)) + if err != nil { + tf.ErrorDiagF(err, "Unable to parse the provided employee_hire_date %q: %+v", v, err) + } + properties.EmployeeHireDate = nullable.NoZero(v.(string)) + } + options := user.CreateUserOperationOptions{ RetryFunc: func(resp *http.Response, o *odata.OData) (bool, error) { if response.WasBadRequest(resp) && o != nil && o.Error != nil { @@ -611,6 +626,14 @@ func userResourceUpdate(ctx context.Context, d *pluginsdk.ResourceData, meta int properties.ShowInAddressList = nullable.NoZero(d.Get("show_in_address_list").(bool)) } + if d.HasChange("employee_hire_date") { + _, err := time.Parse(time.RFC3339, d.Get("employee_hire_date").(string)) + if err != nil { + tf.ErrorDiagF(err, "Unable to parse the provided employee_hire_date %q: %+v", d.Get("employee_hire_date"), err) + } + properties.EmployeeHireDate = nullable.NoZero(d.Get("employee_hire_date").(string)) + } + if _, err = client.UpdateUser(ctx, *id, properties, user.DefaultUpdateUserOperationOptions()); err != nil { // Flag the state as 'partial' to avoid setting `password` from the current config. Since the config is the // only source for this property, if the update fails due to a bad password, the current password will be forgotten @@ -707,6 +730,7 @@ func userResourceRead(ctx context.Context, d *pluginsdk.ResourceData, meta inter "consentProvidedForMinor", "country", "department", + "employeeHireDate", "employeeId", "employeeOrgData", "employeeType", @@ -738,6 +762,7 @@ func userResourceRead(ctx context.Context, d *pluginsdk.ResourceData, meta inter tf.Set(d, "consent_provided_for_minor", uExtra.ConsentProvidedForMinor.GetOrZero()) tf.Set(d, "country", uExtra.Country.GetOrZero()) tf.Set(d, "department", uExtra.Department.GetOrZero()) + tf.Set(d, "employee_hire_date", uExtra.EmployeeHireDate.GetOrZero()) tf.Set(d, "employee_id", uExtra.EmployeeId.GetOrZero()) tf.Set(d, "employee_type", uExtra.EmployeeType.GetOrZero()) tf.Set(d, "external_user_state", uExtra.ExternalUserState.GetOrZero()) diff --git a/internal/services/users/user_resource_test.go b/internal/services/users/user_resource_test.go index 90b08a0a7..b74030055 100644 --- a/internal/services/users/user_resource_test.go +++ b/internal/services/users/user_resource_test.go @@ -228,6 +228,7 @@ resource "azuread_user" "test" { department = "acctestUser-%[1]d-Dept" display_name = "acctestUser-%[1]d-DisplayName" division = "acctestUser-%[1]d-Division" + employee_hire_date = "2018-01-01T01:02:03Z" employee_id = "%[3]s%[3]s" employee_type = "Contractor" fax_number = "(555) 555-5555"