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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 54 additions & 16 deletions src/CareTogether.Api/Controllers/ConfigurationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ public sealed record CurrentFeatureFlags(
bool FamilyScreenPageVersionSwitch
);

public sealed record PutLocationPayload(
LocationConfiguration locationConfiguration,
Guid? copyPoliciesFromLocationId
);
public sealed record PutLocationPayload(
LocationConfiguration locationConfiguration,
Guid? copyPoliciesFromLocationId
);

[ApiController]
[Authorize(
Expand Down Expand Up @@ -310,15 +310,15 @@ [FromBody] PutLocationPayload newLocationPayload
if (!User.IsInRole(SystemConstants.ORGANIZATION_ADMINISTRATOR))
return Forbid();

if (newLocationConfiguration.Id != default)
{
var updatedLocation = await policiesResource.UpsertLocationDefinitionAsync(
organizationId,
newLocationConfiguration
);
return Ok(updatedLocation.OrganizationConfiguration);
}
if (newLocationConfiguration.Id != default)
Comment thread
Rabi94 marked this conversation as resolved.
{
var updatedLocation = await policiesResource.UpsertLocationDefinitionAsync(
organizationId,
newLocationConfiguration
);

return Ok(updatedLocation.OrganizationConfiguration);
}

if (copyPoliciesFromLocationId == Guid.Empty)
return BadRequest(
Expand Down Expand Up @@ -445,6 +445,44 @@ public async Task<ActionResult<CurrentFeatureFlags>> GetLocationFlags(Guid organ
)
);
return Ok(result);
}
}
}
}
}

public sealed record PutOrganizationConfigurationPayload(
ImmutableList<string>? ReferralCloseReasons,
ImmutableList<string>? CaseCloseReasons
);

[ApiController]
[Authorize(
Policies.ForbidAnonymous,
AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme
)]
public class OrganizationConfigurationController : ControllerBase
{
private readonly IPoliciesResource policiesResource;

public OrganizationConfigurationController(IPoliciesResource policiesResource)
{
this.policiesResource = policiesResource;
}

[HttpPut("/api/{organizationId:guid}/[controller]")]
public async Task<ActionResult<OrganizationConfiguration>> PutOrganizationConfiguration(
Guid organizationId,
[FromBody] PutOrganizationConfigurationPayload payload
)
{
if (!User.IsInRole(SystemConstants.ORGANIZATION_ADMINISTRATOR))
return Forbid();

var result = await policiesResource.UpdateOrganizationCloseReasonsAsync(
organizationId,
payload.ReferralCloseReasons,
payload.CaseCloseReasons
);

return Ok(result);
}
}
}
136 changes: 77 additions & 59 deletions src/CareTogether.Api/OData/LiveODataModelController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public sealed record Referral(
DateOnly Opened,
DateOnly? Closed,
string? ReferralSource,
V1CaseCloseReason? CloseReason,
string? CloseReason,
string? PrimaryReasonForReferral
);

Expand Down Expand Up @@ -286,7 +286,7 @@ public sealed record RoleApproval(
string RlsKey
);

public sealed record FamilyRequirementStatus (
public sealed record FamilyRequirementStatus(
Guid OrganizationId,
Guid LocationId,
[property: Key] Guid FamilyId,
Expand Down Expand Up @@ -498,7 +498,9 @@ public async Task<IEnumerable<FamilyRequirementStatus>> GetFamilyRequirementStat

[HttpGet("IndividualRequirementStatuses")]
[EnableQuery]
public async Task<IEnumerable<IndividualRequirementStatus>> GetIndividualRequirementStatusesAsync()
public async Task<
IEnumerable<IndividualRequirementStatus>
> GetIndividualRequirementStatusesAsync()
{
var liveModel = await RenderLiveModelAsync();
return liveModel.IndividualRequirementStatuses;
Expand Down Expand Up @@ -601,7 +603,9 @@ await cache.GetOrAddAsync(
acc.CommunityRoleAssignments.Concat(model.CommunityRoleAssignments),
acc.RoleApprovals.Concat(model.RoleApprovals),
acc.FamilyRequirementStatuses.Concat(model.FamilyRequirementStatuses),
acc.IndividualRequirementStatuses.Concat(model.IndividualRequirementStatuses)
acc.IndividualRequirementStatuses.Concat(
model.IndividualRequirementStatuses
)
)
);

Expand Down Expand Up @@ -685,7 +689,9 @@ bool anonymize
.ToArrayAsync();

var familiesByLocation = visibleAggregatesByLocation
.Where(zipResult => zipResult.Item2 is FamilyRecordsAggregate fra && !fra.Family.Family.IsTestFamily)
.Where(zipResult =>
zipResult.Item2 is FamilyRecordsAggregate fra && !fra.Family.Family.IsTestFamily
)
.Select(zipResult => (zipResult.Item1, (FamilyRecordsAggregate)zipResult.Item2))
.Select(zipResult =>
(
Expand Down Expand Up @@ -925,31 +931,35 @@ await accountsResource.TryGetPersonUserAccountAsync(
{
foreach (var req in family.VolunteerFamilyInfo.CompletedRequirements)
{
familyRequirementStatuses.Add(new FamilyRequirementStatus(
organization.Id,
family.LocationId,
family.Id,
req.RequirementName,
"Complete",
req.CompletedAtUtc,
req.ExpiresAtUtc
));
familyRequirementStatuses.Add(
new FamilyRequirementStatus(
organization.Id,
family.LocationId,
family.Id,
req.RequirementName,
"Complete",
req.CompletedAtUtc,
req.ExpiresAtUtc
)
);
}
}

if (family.VolunteerFamilyInfo?.ExemptedRequirements != null)
{
foreach (var req in family.VolunteerFamilyInfo.ExemptedRequirements)
{
familyRequirementStatuses.Add(new FamilyRequirementStatus(
organization.Id,
family.LocationId,
family.Id,
req.RequirementName,
"Exempted",
req.DueDate,
req.ExemptionExpiresAtUtc
));
familyRequirementStatuses.Add(
new FamilyRequirementStatus(
organization.Id,
family.LocationId,
family.Id,
req.RequirementName,
"Exempted",
req.DueDate,
req.ExemptionExpiresAtUtc
)
);
}
}

Expand All @@ -958,15 +968,17 @@ await accountsResource.TryGetPersonUserAccountAsync(
{
foreach (var missing in family.VolunteerFamilyInfo.MissingRequirements)
{
familyRequirementStatuses.Add(new FamilyRequirementStatus(
organization.Id,
family.LocationId,
family.Id,
missing.ActionName,
"Pending",
null,
null
));
familyRequirementStatuses.Add(
new FamilyRequirementStatus(
organization.Id,
family.LocationId,
family.Id,
missing.ActionName,
"Pending",
null,
null
)
);
}
}
}
Expand All @@ -985,47 +997,53 @@ await accountsResource.TryGetPersonUserAccountAsync(
{
foreach (var req in volunteerData.CompletedRequirements)
{
individualRequirementStatuses.Add(new IndividualRequirementStatus(
organization.Id,
family.LocationId,
personId,
req.RequirementName,
"Complete",
req.CompletedAtUtc,
req.ExpiresAtUtc
));
individualRequirementStatuses.Add(
new IndividualRequirementStatus(
organization.Id,
family.LocationId,
personId,
req.RequirementName,
"Complete",
req.CompletedAtUtc,
req.ExpiresAtUtc
)
);
}
}

if (volunteerData.MissingRequirements != null)
{
foreach (var missing in volunteerData.MissingRequirements)
{
individualRequirementStatuses.Add(new IndividualRequirementStatus(
organization.Id,
family.LocationId,
personId,
missing.ActionName,
"Pending",
null,
null
));
individualRequirementStatuses.Add(
new IndividualRequirementStatus(
organization.Id,
family.LocationId,
personId,
missing.ActionName,
"Pending",
null,
null
)
);
}
}

if (volunteerData.ExemptedRequirements != null)
{
foreach (var exempt in volunteerData.ExemptedRequirements)
{
individualRequirementStatuses.Add(new IndividualRequirementStatus(
organization.Id,
family.LocationId,
personId,
exempt.RequirementName,
"Exempted",
exempt.DueDate,
exempt.ExemptionExpiresAtUtc
));
individualRequirementStatuses.Add(
new IndividualRequirementStatus(
organization.Id,
family.LocationId,
personId,
exempt.RequirementName,
"Exempted",
exempt.DueDate,
exempt.ExemptionExpiresAtUtc
)
);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ V1CaseCommand command
UnassignStaffFromV1Case => Permission.EditV1CaseStaffAssignments,
LinkReferralToCase => Permission.EditV1Case,
CloseReferral => Permission.CloseV1Case,
CloseReferralWithReason => Permission.CloseV1Case,
ReopenReferral => Permission.CloseV1Case,
_ => throw new NotImplementedException(
$"The command type '{command.GetType().FullName}' has not been implemented."
Expand Down Expand Up @@ -943,8 +944,7 @@ ImmutableList<Permission> contextPermissions
? partneringFamilyInfo
.History.Where(activity =>
contextPermissions.Contains(Permission.ViewV1CaseStaffAssignments)
|| activity is not V1CaseStaffAssigned
and not V1CaseStaffUnassigned
|| activity is not V1CaseStaffAssigned and not V1CaseStaffUnassigned
)
.ToImmutableList()
: ImmutableList<Activity>.Empty,
Expand Down
2 changes: 1 addition & 1 deletion src/CareTogether.Core/Managers/SharedContracts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public sealed record V1Case(
Guid Id,
DateTime OpenedAtUtc,
DateTime? ClosedAtUtc,
V1CaseCloseReason? CloseReason,
string? CloseReason,
ImmutableList<Resources.CompletedRequirementInfo> CompletedRequirements,
ImmutableList<Resources.ExemptedRequirementInfo> ExemptedRequirements,
ImmutableList<RequirementDefinition> MissingRequirements,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public sealed record OrganizationConfiguration(
ImmutableList<LocationConfiguration> Locations,
ImmutableList<RoleDefinition> Roles,
ImmutableList<string> CommunityRoles,
ImmutableList<string>? ReferralCloseReasons
ImmutableList<string>? ReferralCloseReasons,
ImmutableList<string>? CaseCloseReasons
);

public sealed record LocationConfiguration(
Expand Down Expand Up @@ -409,6 +410,12 @@ LocationConfiguration LocationConfiguration
LocationConfiguration locationConfiguration
);

Task<OrganizationConfiguration> UpdateOrganizationCloseReasonsAsync(
Guid organizationId,
ImmutableList<string>? referralCloseReasons,
ImmutableList<string>? caseCloseReasons
);

Task<EffectiveLocationPolicy> UpsertEffectiveLocationPolicyAsync(
Guid organizationId,
Guid locationId,
Expand Down
27 changes: 27 additions & 0 deletions src/CareTogether.Core/Resources/Policies/PoliciesResource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,23 @@ LocationConfiguration locationConfiguration
return (Render(newConfig), locationConfiguration);
}

public async Task<OrganizationConfiguration> UpdateOrganizationCloseReasonsAsync(
Guid organizationId,
ImmutableList<string>? referralCloseReasons,
ImmutableList<string>? caseCloseReasons
)
{
var config = await configurationStore.GetAsync(organizationId, Guid.Empty, CONFIG);
var newConfig = config with
{
ReferralCloseReasons = referralCloseReasons,
CaseCloseReasons = caseCloseReasons,
};

await configurationStore.UpsertAsync(organizationId, Guid.Empty, CONFIG, newConfig);
return Render(newConfig);
}

public async Task<EffectiveLocationPolicy> UpsertEffectiveLocationPolicyAsync(
Guid organizationId,
Guid locationId,
Expand Down Expand Up @@ -250,6 +267,15 @@ public async Task<OrganizationSecrets> GetOrganizationSecretsAsync(Guid organiza
"Need met"
);

private static readonly ImmutableList<string> DefaultCaseCloseReasons =
ImmutableList.Create(
"Not appropriate",
"No capacity",
"No longer needed",
"Resourced",
"Need met"
);

private OrganizationConfiguration Render(OrganizationConfiguration config) =>
config with
{
Expand All @@ -271,6 +297,7 @@ config with
)
),
ReferralCloseReasons = config.ReferralCloseReasons ?? DefaultReferralCloseReasons,
CaseCloseReasons = config.CaseCloseReasons ?? DefaultCaseCloseReasons,
};
}
}
Loading