Skip to content
Merged
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
21 changes: 21 additions & 0 deletions Core/Resgrid.Localization/Areas/User/Contacts/Contacts.en.resx
Original file line number Diff line number Diff line change
Expand Up @@ -483,4 +483,25 @@
<data name="EditContact" xml:space="preserve">
<value>Edit Contact</value>
</data>
<data name="Routes" xml:space="preserve">
<value>Routes</value>
</data>
<data name="Route" xml:space="preserve">
<value>Route</value>
</data>
<data name="StopName" xml:space="preserve">
<value>Stop Name</value>
</data>
<data name="PriorityNormal" xml:space="preserve">
<value>Normal</value>
</data>
<data name="PriorityHigh" xml:space="preserve">
<value>High</value>
</data>
<data name="PriorityCritical" xml:space="preserve">
<value>Critical</value>
</data>
<data name="PriorityOptional" xml:space="preserve">
<value>Optional</value>
</data>
</root>
70 changes: 70 additions & 0 deletions Core/Resgrid.Localization/Areas/User/Routes/Routes.en.resx
Original file line number Diff line number Diff line change
Expand Up @@ -339,4 +339,74 @@
<data name="StopLabel" xml:space="preserve">
<value>Stop</value>
</data>
<!-- Add Stop Modal -->
<data name="AddStop" xml:space="preserve">
<value>Add Stop</value>
</data>
<data name="StopTypeManual" xml:space="preserve">
<value>Manual</value>
</data>
<data name="StopTypeScheduledCall" xml:space="preserve">
<value>Scheduled Call</value>
</data>
<data name="StopTypeWaypoint" xml:space="preserve">
<value>Waypoint</value>
</data>
<data name="LinkedCall" xml:space="preserve">
<value>Linked Call</value>
</data>
<data name="LoadingCalls" xml:space="preserve">
<value>Loading calls...</value>
</data>
<data name="PriorityNormal" xml:space="preserve">
<value>Normal</value>
</data>
<data name="PriorityHigh" xml:space="preserve">
<value>High</value>
</data>
<data name="PriorityCritical" xml:space="preserve">
<value>Critical</value>
</data>
<data name="PriorityOptional" xml:space="preserve">
<value>Optional</value>
</data>
<data name="Find" xml:space="preserve">
<value>Find</value>
</data>
<data name="What3Words" xml:space="preserve">
<value>What3Words</value>
</data>
<data name="Location" xml:space="preserve">
<value>Location</value>
</data>
<data name="ClickMapToSetLocation" xml:space="preserve">
<value>Click the map to set location, or use address / What3Words above.</value>
</data>
<data name="PlannedArrival" xml:space="preserve">
<value>Planned Arrival</value>
</data>
<data name="PlannedDeparture" xml:space="preserve">
<value>Planned Departure</value>
</data>
<data name="EstDwellMinutes" xml:space="preserve">
<value>Est. Dwell (min)</value>
</data>
<data name="SelectContact" xml:space="preserve">
<value>Select Contact</value>
</data>
<data name="SelectContactPlaceholder" xml:space="preserve">
<value>-- Type manually or select existing --</value>
</data>
<data name="ContactAutofillHelp" xml:space="preserve">
<value>Selecting a contact auto-fills name and number below.</value>
</data>
<data name="ContactName" xml:space="preserve">
<value>Contact Name</value>
</data>
<data name="ContactNumber" xml:space="preserve">
<value>Contact Number</value>
</data>
<data name="Notes" xml:space="preserve">
<value>Notes</value>
</data>
</root>
1 change: 1 addition & 0 deletions Core/Resgrid.Model/Repositories/IRouteStopsRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public interface IRouteStopsRepository : IRepository<RouteStop>
{
Task<IEnumerable<RouteStop>> GetStopsByRoutePlanIdAsync(string routePlanId);
Task<IEnumerable<RouteStop>> GetStopsByCallIdAsync(int callId);
Task<IEnumerable<RouteStop>> GetStopsByContactIdAsync(string contactId);
}
}
2 changes: 2 additions & 0 deletions Core/Resgrid.Model/RouteStop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public class RouteStop : IEntity

public string ContactNumber { get; set; }

public string ContactId { get; set; }

public string Notes { get; set; }

public bool IsDeleted { get; set; }
Expand Down
1 change: 1 addition & 0 deletions Core/Resgrid.Model/Services/IRouteService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public interface IRouteService
// Route Stop CRUD
Task<RouteStop> SaveRouteStopAsync(RouteStop routeStop, CancellationToken cancellationToken = default);
Task<List<RouteStop>> GetRouteStopsForPlanAsync(string routePlanId);
Task<List<RouteStop>> GetRouteStopsForContactAsync(string contactId, int departmentId);
Task<bool> ReorderRouteStopsAsync(string routePlanId, List<string> orderedStopIds, CancellationToken cancellationToken = default);
Task<bool> DeleteRouteStopAsync(string routeStopId, CancellationToken cancellationToken = default);

Expand Down
12 changes: 12 additions & 0 deletions Core/Resgrid.Services/RouteService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ public async Task<List<RouteStop>> GetRouteStopsForPlanAsync(string routePlanId)
return stops?.Where(x => !x.IsDeleted).OrderBy(x => x.StopOrder).ToList() ?? new List<RouteStop>();
}

public async Task<List<RouteStop>> GetRouteStopsForContactAsync(string contactId, int departmentId)
{
var stops = await _routeStopsRepository.GetStopsByContactIdAsync(contactId);
if (stops == null)
return new List<RouteStop>();

var plans = await _routePlansRepository.GetRoutePlansByDepartmentIdAsync(departmentId);
var planIds = plans?.Where(p => !p.IsDeleted).Select(p => p.RoutePlanId).ToHashSet() ?? new HashSet<string>();

return stops.Where(s => !s.IsDeleted && planIds.Contains(s.RoutePlanId)).ToList();
}

public async Task<bool> ReorderRouteStopsAsync(string routePlanId, List<string> orderedStopIds, CancellationToken cancellationToken = default)
{
var stops = await _routeStopsRepository.GetStopsByRoutePlanIdAsync(routePlanId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using FluentMigrator;

namespace Resgrid.Providers.Migrations.Migrations
{
[Migration(54)]
public class M0054_AddContactIdToRouteStops : Migration
{
public override void Up()
{
Alter.Table("RouteStops")
.AddColumn("ContactId").AsString(128).Nullable();
}

public override void Down()
{
Delete.Column("ContactId").FromTable("RouteStops");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using FluentMigrator;

namespace Resgrid.Providers.MigrationsPg.Migrations
{
[Migration(54)]
public class M0054_AddContactIdToRouteStopsPg : Migration
{
public override void Up()
{
Alter.Table("routestops")
.AddColumn("contactid").AsCustom("citext").Nullable();
}

public override void Down()
{
Delete.Column("contactid").FromTable("routestops");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ protected SqlConfiguration() { }
public string SelectActiveRoutePlansByDepartmentIdQuery { get; set; }
public string SelectRouteStopsByRoutePlanIdQuery { get; set; }
public string SelectRouteStopsByCallIdQuery { get; set; }
public string SelectRouteStopsByContactIdQuery { get; set; }
public string SelectRouteSchedulesByRoutePlanIdQuery { get; set; }
public string SelectActiveSchedulesDueQuery { get; set; }
public string SelectRouteInstancesByDepartmentIdQuery { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Resgrid.Model;
using Resgrid.Model.Repositories.Queries.Contracts;
using Resgrid.Repositories.DataRepository.Configs;
using Resgrid.Repositories.DataRepository.Extensions;

namespace Resgrid.Repositories.DataRepository.Queries.Routes
{
public class SelectRouteStopsByContactIdQuery : ISelectQuery
{
private readonly SqlConfiguration _sqlConfiguration;
public SelectRouteStopsByContactIdQuery(SqlConfiguration sqlConfiguration)
{
_sqlConfiguration = sqlConfiguration;
}

public string GetQuery()
{
var query = _sqlConfiguration.SelectRouteStopsByContactIdQuery
.ReplaceQueryParameters(_sqlConfiguration, _sqlConfiguration.SchemaName,
_sqlConfiguration.RouteStopsTableName,
_sqlConfiguration.ParameterNotation,
new string[] { "%CONTACTID%" },
new string[] { "ContactId" });

return query;
}

public string GetQuery<TEntity>() where TEntity : class, IEntity
{
throw new System.NotImplementedException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,41 @@ public async Task<IEnumerable<RouteStop>> GetStopsByCallIdAsync(int callId)
throw;
}
}

public async Task<IEnumerable<RouteStop>> GetStopsByContactIdAsync(string contactId)
{
try
{
var selectFunction = new Func<DbConnection, Task<IEnumerable<RouteStop>>>(async x =>
{
var dynamicParameters = new DynamicParametersExtension();
dynamicParameters.Add("ContactId", contactId);

var query = _queryFactory.GetQuery<SelectRouteStopsByContactIdQuery>();

return await x.QueryAsync<RouteStop>(sql: query, param: dynamicParameters, transaction: _unitOfWork.Transaction);
});

DbConnection conn = null;
if (_unitOfWork?.Connection == null)
{
using (conn = _connectionProvider.Create())
{
await conn.OpenAsync();
return await selectFunction(conn);
}
}
else
{
conn = _unitOfWork.CreateOrGetConnection();
return await selectFunction(conn);
}
}
catch (Exception ex)
{
Logging.LogException(ex);
throw;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1515,6 +1515,10 @@ DELETE FROM %SCHEMA%.%TABLENAME%
SELECT *
FROM %SCHEMA%.%TABLENAME%
WHERE CallId = %CALLID% AND IsDeleted = false";
SelectRouteStopsByContactIdQuery = @"
SELECT *
FROM %SCHEMA%.%TABLENAME%
WHERE ContactId = %CONTACTID% AND IsDeleted = false";
SelectRouteSchedulesByRoutePlanIdQuery = @"
SELECT *
FROM %SCHEMA%.%TABLENAME%
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,10 @@ DELETE FROM %SCHEMA%.%TABLENAME%
SELECT *
FROM %SCHEMA%.%TABLENAME%
WHERE [CallId] = %CALLID% AND [IsDeleted] = 0";
SelectRouteStopsByContactIdQuery = @"
SELECT *
FROM %SCHEMA%.%TABLENAME%
WHERE [ContactId] = %CONTACTID% AND [IsDeleted] = 0";
SelectRouteSchedulesByRoutePlanIdQuery = @"
SELECT *
FROM %SCHEMA%.%TABLENAME%
Expand Down
16 changes: 15 additions & 1 deletion Web/Resgrid.Web/Areas/User/Controllers/ContactsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@ public class ContactsController : SecureBaseController
private readonly IUserDefinedFieldsService _userDefinedFieldsService;
private readonly IUdfRenderingService _udfRenderingService;
private readonly IDepartmentGroupsService _departmentGroupsService;
private readonly IRouteService _routeService;

public ContactsController(IContactsService contactsService, IDepartmentsService departmentsService, IUserProfileService userProfileService,
IAddressService addressService, IEventAggregator eventAggregator, ICallsService callsService, IAuthorizationService authorizationService,
IUserDefinedFieldsService userDefinedFieldsService, IUdfRenderingService udfRenderingService,
IDepartmentGroupsService departmentGroupsService)
IDepartmentGroupsService departmentGroupsService, IRouteService routeService)
{
_contactsService = contactsService;
_departmentsService = departmentsService;
Expand All @@ -53,6 +54,7 @@ public ContactsController(IContactsService contactsService, IDepartmentsService
_userDefinedFieldsService = userDefinedFieldsService;
_udfRenderingService = udfRenderingService;
_departmentGroupsService = departmentGroupsService;
_routeService = routeService;
}

#endregion Private Members and Constructors
Expand Down Expand Up @@ -128,6 +130,18 @@ public async Task<IActionResult> View(string contactId)

model.Notes = await _contactsService.GetContactNotesByContactIdAsync(contactId, DepartmentId);

model.RouteStops = await _routeService.GetRouteStopsForContactAsync(contactId, DepartmentId) ?? new List<RouteStop>();
if (model.RouteStops.Count > 0)
{
var planIds = model.RouteStops.Select(s => s.RoutePlanId).Distinct().ToList();
var allPlans = await _routeService.GetRoutePlansForDepartmentAsync(DepartmentId);
model.RoutePlans = allPlans.Where(p => planIds.Contains(p.RoutePlanId)).ToList();
}
else
{
model.RoutePlans = new List<RoutePlan>();
}

var udfDefinition = await _userDefinedFieldsService.GetActiveDefinitionAsync(DepartmentId, (int)UdfEntityType.Contact);
if (udfDefinition != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public async Task<IActionResult> SearchZones(string term)

var zones = await _indoorMapService.SearchZonesAsync(DepartmentId, term);

var results = zones.Select(z => new
var results = (zones ?? Enumerable.Empty<Resgrid.Model.IndoorMapZone>()).Select(z => new
{
id = z.IndoorMapZoneId,
text = z.Name,
Expand Down
Loading
Loading