diff --git a/source/backend/api/Areas/Takes/Controllers/TakeController.cs b/source/backend/api/Areas/Takes/Controllers/TakeController.cs
index 6061efe24c..162dffc5c4 100644
--- a/source/backend/api/Areas/Takes/Controllers/TakeController.cs
+++ b/source/backend/api/Areas/Takes/Controllers/TakeController.cs
@@ -1,15 +1,18 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using MapsterMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
+using Pims.Api.Helpers.Exceptions;
using Pims.Api.Models.Concepts.Take;
using Pims.Api.Policies;
using Pims.Api.Services;
using Pims.Core.Extensions;
using Pims.Core.Json;
using Pims.Dal.Entities;
+using Pims.Dal.Exceptions;
using Pims.Dal.Security;
using Swashbuckle.AspNetCore.Annotations;
@@ -104,28 +107,98 @@ public IActionResult GetTakesByPropertyId([FromRoute] long fileId, [FromRoute] l
}
///
- /// Update the list of takes associated to a property within an acquisition file.
+ /// Add the passed take to the acquisition property with the given id.
///
///
- [HttpPut("acquisition/property/{acquisitionFilePropertyId:long}")]
+ [HttpPost("acquisition/property/{acquisitionFilePropertyId:long}/takes")]
[HasPermission(Permissions.AcquisitionFileEdit, Permissions.PropertyEdit)]
[Produces("application/json")]
- [ProducesResponseType(typeof(IEnumerable), 200)]
+ [ProducesResponseType(typeof(TakeModel), 201)]
+ [SwaggerOperation(Tags = new[] { "take" })]
+ [TypeFilter(typeof(NullJsonResultFilter))]
+ public IActionResult AddAcquisitionPropertyTake(long acquisitionFilePropertyId, [FromBody] TakeModel take)
+ {
+ _logger.LogInformation(
+ "Request received by Controller: {Controller}, Action: {ControllerAction}, User: {User}, DateTime: {DateTime}",
+ nameof(TakeController),
+ nameof(AddAcquisitionPropertyTake),
+ User.GetUsername(),
+ DateTime.Now);
+
+ if (acquisitionFilePropertyId != take.PropertyAcquisitionFileId)
+ {
+ throw new BadRequestException("Invalid acquisition file property id.");
+ }
+
+ _logger.LogInformation("Dispatching to service: {Service}", _takeService.GetType());
+
+ var addedTake = _takeService.AddAcquisitionPropertyTake(acquisitionFilePropertyId, _mapper.Map(take));
+ return new JsonResult(_mapper.Map(addedTake));
+ }
+
+ ///
+ /// Update a take with the given take and acquisition file property id with the passed take.
+ ///
+ ///
+ [HttpPut("acquisition/property/{acquisitionFilePropertyId:long}/takes/{takeId:long}")]
+ [HasPermission(Permissions.AcquisitionFileEdit, Permissions.PropertyEdit)]
+ [Produces("application/json")]
+ [ProducesResponseType(typeof(TakeModel), 200)]
[SwaggerOperation(Tags = new[] { "take" })]
[TypeFilter(typeof(NullJsonResultFilter))]
- public IActionResult UpdateAcquisitionPropertyTakes(long acquisitionFilePropertyId, [FromBody] IEnumerable takes)
+ public IActionResult UpdateAcquisitionPropertyTake(long acquisitionFilePropertyId, long takeId, [FromBody] TakeModel take)
{
_logger.LogInformation(
"Request received by Controller: {Controller}, Action: {ControllerAction}, User: {User}, DateTime: {DateTime}",
nameof(TakeController),
- nameof(UpdateAcquisitionPropertyTakes),
+ nameof(UpdateAcquisitionPropertyTake),
User.GetUsername(),
DateTime.Now);
+ if (acquisitionFilePropertyId != take.PropertyAcquisitionFileId)
+ {
+ throw new BadRequestException("Invalid acquisition file property id.");
+ }
+ else if (takeId != take.Id)
+ {
+ throw new BadRequestException("Invalid take id.");
+ }
+
_logger.LogInformation("Dispatching to service: {Service}", _takeService.GetType());
- var updatedTakes = _takeService.UpdateAcquisitionPropertyTakes(acquisitionFilePropertyId, _mapper.Map>(takes));
- return new JsonResult(_mapper.Map>(updatedTakes));
+ var updatedTake = _takeService.UpdateAcquisitionPropertyTake(acquisitionFilePropertyId, _mapper.Map(take));
+ return new JsonResult(_mapper.Map(updatedTake));
+ }
+
+ ///
+ /// Delete a take with the given take id and acquisition file property id.
+ ///
+ [HttpDelete("acquisition/property/{acquisitionFilePropertyId:long}/takes/{takeId:long}")]
+ [HasPermission(Permissions.AcquisitionFileEdit, Permissions.PropertyEdit)]
+ [Produces("application/json")]
+ [ProducesResponseType(typeof(void), 200)]
+ [SwaggerOperation(Tags = new[] { "take" })]
+ [TypeFilter(typeof(NullJsonResultFilter))]
+ public void DeleteAcquisitionPropertyTake(long acquisitionFilePropertyId, long takeId, [FromQuery] string[] userOverrideCodes)
+ {
+ _logger.LogInformation(
+ "Request received by Controller: {Controller}, Action: {ControllerAction}, User: {User}, DateTime: {DateTime}",
+ nameof(TakeController),
+ nameof(DeleteAcquisitionPropertyTake),
+ User.GetUsername(),
+ DateTime.Now);
+
+ _logger.LogInformation("Dispatching to service: {Service}", _takeService.GetType());
+ var existingTake = _takeService.GetById(takeId);
+ if (existingTake.PropertyAcquisitionFileId != acquisitionFilePropertyId)
+ {
+ throw new BadRequestException("Invalid acquisition file property id.");
+ }
+ var deleted = _takeService.DeleteAcquisitionPropertyTake(takeId, userOverrideCodes.Select(oc => UserOverrideCode.Parse(oc)));
+ if (!deleted)
+ {
+ throw new InvalidOperationException($"Failed to delete take {takeId}.");
+ }
}
///
@@ -152,6 +225,34 @@ public IActionResult GetTakesCountByPropertyId([FromRoute] long propertyId)
return new JsonResult(count);
}
+ ///
+ /// GGet a take by id.
+ ///
+ ///
+ [HttpGet("acquisition/property/{acquisitionFilePropertyId:long}/takes/{takeId:long}")]
+ [HasPermission(Permissions.AcquisitionFileView, Permissions.PropertyView)]
+ [Produces("application/json")]
+ [ProducesResponseType(typeof(int), 200)]
+ [SwaggerOperation(Tags = new[] { "take" })]
+ public IActionResult GetTakeByPropertyFileId(long acquisitionFilePropertyId, long takeId)
+ {
+ _logger.LogInformation(
+ "Request received by Controller: {Controller}, Action: {ControllerAction}, User: {User}, DateTime: {DateTime}",
+ nameof(TakeController),
+ nameof(GetTakesCountByPropertyId),
+ User.GetUsername(),
+ DateTime.Now);
+
+ _logger.LogInformation("Dispatching to service: {Service}", _takeService.GetType());
+
+ var take = _takeService.GetById(takeId);
+ if(take.PropertyAcquisitionFileId != acquisitionFilePropertyId)
+ {
+ throw new BadRequestException("Invalid acquisition file property id.");
+ }
+ return new JsonResult(_mapper.Map(take));
+ }
+
#endregion
}
}
diff --git a/source/backend/api/Services/ITakeService.cs b/source/backend/api/Services/ITakeService.cs
index 5758235c33..6548486492 100644
--- a/source/backend/api/Services/ITakeService.cs
+++ b/source/backend/api/Services/ITakeService.cs
@@ -1,16 +1,24 @@
using System.Collections.Generic;
using Pims.Dal.Entities;
+using Pims.Dal.Exceptions;
namespace Pims.Api.Services
{
public interface ITakeService
{
+
+ PimsTake GetById(long takeId);
+
+ PimsTake AddAcquisitionPropertyTake(long acquisitionFilePropertyId, PimsTake take);
+
+ PimsTake UpdateAcquisitionPropertyTake(long acquisitionFilePropertyId, PimsTake take);
+
+ bool DeleteAcquisitionPropertyTake(long takeId, IEnumerable userOverrides);
+
IEnumerable GetByFileId(long fileId);
IEnumerable GetByPropertyId(long fileId, long acquisitionFilePropertyId);
int GetCountByPropertyId(long propertyId);
-
- IEnumerable UpdateAcquisitionPropertyTakes(long acquisitionFilePropertyId, IEnumerable takes);
}
}
diff --git a/source/backend/api/Services/TakeService.cs b/source/backend/api/Services/TakeService.cs
index fb5698f7b1..cad1988544 100644
--- a/source/backend/api/Services/TakeService.cs
+++ b/source/backend/api/Services/TakeService.cs
@@ -7,6 +7,7 @@
using Pims.Api.Models.CodeTypes;
using Pims.Core.Exceptions;
using Pims.Dal.Entities;
+using Pims.Dal.Exceptions;
using Pims.Dal.Helpers.Extensions;
using Pims.Dal.Repositories;
using Pims.Dal.Security;
@@ -43,6 +44,13 @@ public TakeService(
_propertyRepository = propertyRepository;
}
+ public PimsTake GetById(long takeId)
+ {
+ _logger.LogInformation("Getting take with takeId {takeId}", takeId);
+ _user.ThrowIfNotAuthorized(Permissions.PropertyView, Permissions.AcquisitionFileView);
+ return _takeRepository.GetById(takeId);
+ }
+
public IEnumerable GetByFileId(long fileId)
{
_logger.LogInformation("Getting takes with fileId {fileId}", fileId);
@@ -64,65 +72,176 @@ public int GetCountByPropertyId(long propertyId)
return _takeRepository.GetCountByPropertyId(propertyId);
}
- public IEnumerable UpdateAcquisitionPropertyTakes(long acquisitionFilePropertyId, IEnumerable takes)
+ public PimsTake AddAcquisitionPropertyTake(long acquisitionFilePropertyId, PimsTake take)
{
- _logger.LogInformation("updating takes with propertyFileId {propertyFileId}", acquisitionFilePropertyId);
+ _logger.LogInformation("adding take with propertyFileId {propertyFileId}", acquisitionFilePropertyId);
_user.ThrowIfNotAuthorized(Permissions.PropertyView, Permissions.AcquisitionFileView);
- var currentAcquistionFile = _acqFileRepository.GetByAcquisitionFilePropertyId(acquisitionFilePropertyId);
+ ValidateTakeRules(acquisitionFilePropertyId, take);
+
+ // Add take
+ var addedTake = _takeRepository.AddTake(take);
+
+ RecalculateOwnership(acquisitionFilePropertyId, take);
+
+ _takeRepository.CommitTransaction();
+ return addedTake;
+ }
+
+ public PimsTake UpdateAcquisitionPropertyTake(long acquisitionFilePropertyId, PimsTake take)
+ {
+ _logger.LogInformation("updating take with propertyFileId {propertyFileId}", acquisitionFilePropertyId);
+ _user.ThrowIfNotAuthorized(Permissions.PropertyView, Permissions.AcquisitionFileView);
+
+ ValidateTakeRules(acquisitionFilePropertyId, take);
+
+ // Update take
+ var updatedTake = _takeRepository.UpdateTake(take);
+
+ RecalculateOwnership(acquisitionFilePropertyId, take);
+
+ _takeRepository.CommitTransaction();
+ return updatedTake;
+ }
+
+ public bool DeleteAcquisitionPropertyTake(long takeId, IEnumerable userOverrides)
+ {
+ _logger.LogInformation("deleting take with {takeId}", takeId);
+ _user.ThrowIfNotAuthorized(Permissions.PropertyView, Permissions.AcquisitionFileView);
+
+ var takeToDelete = _takeRepository.GetById(takeId);
+ var propertyWithAssociations = _propertyRepository.GetAllAssociationsById(takeToDelete.PropertyAcquisitionFile.PropertyId);
+ var currentAcquisitionFile = _acqFileRepository.GetByAcquisitionFilePropertyId(takeToDelete.PropertyAcquisitionFileId);
+ var allTakesForProperty = _takeRepository.GetAllByPropertyId(takeToDelete.PropertyAcquisitionFile.PropertyId);
+ if ((!_statusSolver.CanEditTakes(Enum.Parse(currentAcquisitionFile.AcquisitionFileStatusTypeCode)) || takeToDelete.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString())
+ && !_user.HasPermission(Permissions.SystemAdmin))
+ {
+ throw new BusinessRuleViolationException("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion.");
+ }
+ else if(propertyWithAssociations?.PimsDispositionFileProperties?.Any(d => d.DispositionFile.DispositionFileStatusTypeCode == DispositionFileStatusTypes.COMPLETE.ToString()) == true)
+ {
+ throw new BusinessRuleViolationException("You cannot delete a take that has a completed disposition attached to the same property.");
+ }
+ else if (propertyWithAssociations?.IsRetired == true)
+ {
+ throw new BusinessRuleViolationException("You cannot delete a take from a retired property.");
+ }
+
+ // user overrides
+ if (takeToDelete.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString() && _user.HasPermission(Permissions.SystemAdmin))
+ {
+ if (propertyWithAssociations?.PimsDispositionFileProperties?.Any(d => d.DispositionFile.DispositionFileStatusTypeCode == DispositionFileStatusTypes.ACTIVE.ToString()) == true && !userOverrides.Contains(UserOverrideCode.DeleteTakeActiveDisposition))
+ {
+ throw new UserOverrideException(UserOverrideCode.DeleteTakeActiveDisposition, "You are deleting a take. Property ownership state will be recalculated based upon any remaining completed takes. It should be noted that one or more related dispositions are in progress that should also be reviewed. \n\nDo you want to acknowledge and proceed?");
+ }
+ else if (allTakesForProperty.Count(t => !IsTakeExpired(t) && t.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString()) == 1 && allTakesForProperty.FirstOrDefault().TakeId == takeId && !userOverrides.Contains(UserOverrideCode.DeleteLastTake))
+ {
+ throw new UserOverrideException(UserOverrideCode.DeleteLastTake, "You are deleting the last non-expired completed take on this property. This property will become a property of interest.\n\nDo you want to acknowledge and proceed?");
+ }
+ else if (!userOverrides.Contains(UserOverrideCode.DeleteCompletedTake) && !userOverrides.Contains(UserOverrideCode.DeleteLastTake) && !userOverrides.Contains(UserOverrideCode.DeleteTakeActiveDisposition))
+ {
+ throw new UserOverrideException(UserOverrideCode.DeleteCompletedTake, "You are deleting a completed take. Property ownership state will be recalculated based upon any remaining completed takes.\n\nDo you want to acknowledge and proceed?");
+ }
+ }
+
+ var wasTakeDeleted = _takeRepository.TryDeleteTake(takeId);
+
+ if (wasTakeDeleted)
+ {
+ // Evaluate if the property needs to be updated
+ var currentProperty = _acqFileRepository.GetProperty(takeToDelete.PropertyAcquisitionFileId);
+ var currentTakes = _takeRepository.GetAllByPropertyId(currentProperty.PropertyId);
+
+ var completedTakes = currentTakes
+ .Where(x => x.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString() && x.TakeId != takeId).ToList();
+
+ if (completedTakes.Count > 0 || takeToDelete.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString())
+ {
+ if (_takeInteractionSolver.ResultsInOwnedProperty(completedTakes))
+ {
+ _propertyRepository.TransferFileProperty(currentProperty, true);
+ }
+ else
+ {
+ _propertyRepository.TransferFileProperty(currentProperty, false);
+ }
+ }
+ }
+
+ _takeRepository.CommitTransaction();
+ return wasTakeDeleted;
+ }
+
+ private static bool IsTakeExpired(PimsTake take)
+ {
+ return (take.IsActiveLease && take.ActiveLeaseEndDt > DateOnly.FromDateTime(DateTime.Now))
+ || (take.IsNewLandAct && take.LandActEndDt > DateOnly.FromDateTime(DateTime.Now))
+ || (take.IsNewLicenseToConstruct && take.LtcEndDt > DateOnly.FromDateTime(DateTime.Now))
+ || (take.IsNewInterestInSrw && take.SrwEndDt > DateOnly.FromDateTime(DateTime.Now));
+ }
+
+ private void ValidateTakeRules(long acquisitionFilePropertyId, PimsTake take)
+ {
var currentFilePropertyTakes = _takeRepository.GetAllByPropertyAcquisitionFileId(acquisitionFilePropertyId);
+ var currentAcquistionFile = _acqFileRepository.GetByAcquisitionFilePropertyId(acquisitionFilePropertyId);
var currentAcquisitionStatus = Enum.Parse(currentAcquistionFile.AcquisitionFileStatusTypeCode);
if (!_statusSolver.CanEditTakes(currentAcquisitionStatus) && !_user.HasPermission(Permissions.SystemAdmin))
{
throw new BusinessRuleViolationException("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion.");
}
- else if (takes.Any(t => t.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString() && t.CompletionDt == null))
+ else if (take.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString() && take.CompletionDt == null)
{
throw new BusinessRuleViolationException("A completed take must have a completion date.");
}
- else if (takes.Any(t => t.IsNewLandAct && t.LandActEndDt != null && (t.LandActTypeCode == LandActTypes.CROWN_GRANT.ToString() || t.LandActTypeCode == LandActTypes.TRANSFER_OF_ADMIN_AND_CONTROL.ToString())))
+ else if (take.IsNewLandAct && take.LandActEndDt != null && (take.LandActTypeCode == LandActTypes.CROWN_GRANT.ToString() || take.LandActTypeCode == LandActTypes.TRANSFER_OF_ADMIN_AND_CONTROL.ToString()))
{
throw new BusinessRuleViolationException("'Crown Grant' and 'Transfer' Land Acts cannot have an end date.");
}
else
{
- // Complete Takes can only be deleted or set to InProgress by Admins when File is Active/Draft
+ // Complete Takes can only be set to InProgress by Admins when File is Active/Draft
var currentCompleteTakes = currentFilePropertyTakes
.Where(x => x.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString()).ToList();
if (currentCompleteTakes.Count > 0)
{
- foreach (var completeTake in currentCompleteTakes)
+ var updatedTake = currentCompleteTakes.FirstOrDefault(x => x.TakeId == take.TakeId);
+ if (!_user.HasPermission(Permissions.SystemAdmin) && (updatedTake is not null && updatedTake.TakeStatusTypeCode != take.TakeStatusTypeCode))
{
- // Validate that the current completed take can only by updated by a sysadmin
- var updatedTake = takes.FirstOrDefault(x => x.TakeId == completeTake.TakeId);
- if (!_user.HasPermission(Permissions.SystemAdmin) && (updatedTake is null || (updatedTake is not null && updatedTake.TakeStatusTypeCode != completeTake.TakeStatusTypeCode)))
- {
- throw new BusinessRuleViolationException("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion.");
- }
+ throw new BusinessRuleViolationException("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion.");
}
}
}
+ }
- // Update takes
- _takeRepository.UpdateAcquisitionPropertyTakes(acquisitionFilePropertyId, takes);
-
+ private void RecalculateOwnership(long acquisitionFilePropertyId, PimsTake take)
+ {
// Evaluate if the property needs to be updated
var currentProperty = _acqFileRepository.GetProperty(acquisitionFilePropertyId);
var currentTakes = _takeRepository.GetAllByPropertyId(currentProperty.PropertyId);
- var completedTakes = currentTakes.Union(takes)
+ var allTakes = currentTakes;
+ if (take != null)
+ {
+ allTakes = allTakes.Append(take);
+ }
+
+ var completedTakes = allTakes
.Where(x => x.TakeStatusTypeCode == AcquisitionTakeStatusTypes.COMPLETE.ToString()).ToList();
- if (_takeInteractionSolver.ResultsInOwnedProperty(completedTakes))
+ if (completedTakes.Count > 0)
{
- _propertyRepository.TransferFileProperty(currentProperty, true);
+ if (_takeInteractionSolver.ResultsInOwnedProperty(completedTakes))
+ {
+ _propertyRepository.TransferFileProperty(currentProperty, true);
+ }
+ else
+ {
+ _propertyRepository.TransferFileProperty(currentProperty, false);
+ }
}
-
- _takeRepository.CommitTransaction();
- return _takeRepository.GetAllByPropertyAcquisitionFileId(acquisitionFilePropertyId);
}
}
}
diff --git a/source/backend/apimodels/CodeTypes/TakeTypes.cs b/source/backend/apimodels/CodeTypes/TakeTypes.cs
new file mode 100644
index 0000000000..843e528b32
--- /dev/null
+++ b/source/backend/apimodels/CodeTypes/TakeTypes.cs
@@ -0,0 +1,15 @@
+using System.Runtime.Serialization;
+using System.Text.Json.Serialization;
+
+namespace Pims.Api.Models.CodeTypes
+{
+ [JsonConverter(typeof(JsonStringEnumMemberConverter))]
+ public enum TakeTypes
+ {
+ [EnumMember(Value = "TOTAL")]
+ TOTAL,
+
+ [EnumMember(Value = "PARTIAL")]
+ PARTIAL,
+ }
+}
diff --git a/source/backend/dal/Exceptions/OverrideExceptions.cs b/source/backend/dal/Exceptions/OverrideExceptions.cs
index cfd4fa58b7..df35cd7bec 100644
--- a/source/backend/dal/Exceptions/OverrideExceptions.cs
+++ b/source/backend/dal/Exceptions/OverrideExceptions.cs
@@ -50,6 +50,21 @@ public static UserOverrideCode DisposeOfProperties
get { return new UserOverrideCode("DISPOSE_OF_PROPERTIES"); }
}
+ public static UserOverrideCode DeleteCompletedTake
+ {
+ get { return new UserOverrideCode("DELETE_COMPLETED_TAKE"); }
+ }
+
+ public static UserOverrideCode DeleteLastTake
+ {
+ get { return new UserOverrideCode("DELETE_LAST_TAKE"); }
+ }
+
+ public static UserOverrideCode DeleteTakeActiveDisposition
+ {
+ get { return new UserOverrideCode("DELETE_TAKE_ACTIVE_DISPOSITION"); }
+ }
+
public string Code { get; private set; }
private static List UserOverrideCodes => new List()
@@ -63,6 +78,9 @@ public static UserOverrideCode DisposeOfProperties
UserOverrideCode.DisposingPropertyNotInventoried,
UserOverrideCode.DispositionFileFinalStatus,
UserOverrideCode.DisposeOfProperties,
+ UserOverrideCode.DeleteCompletedTake,
+ UserOverrideCode.DeleteLastTake,
+ UserOverrideCode.DeleteTakeActiveDisposition,
};
private UserOverrideCode(string code)
diff --git a/source/backend/dal/Repositories/Interfaces/ITakeRepository.cs b/source/backend/dal/Repositories/Interfaces/ITakeRepository.cs
index c76900118c..69bb5c2169 100644
--- a/source/backend/dal/Repositories/Interfaces/ITakeRepository.cs
+++ b/source/backend/dal/Repositories/Interfaces/ITakeRepository.cs
@@ -10,13 +10,19 @@ public interface ITakeRepository : IRepository
{
IEnumerable GetAllByAcquisitionFileId(long fileId);
- IEnumerable GetAllByAcqPropertyId(long fileId, long acquisitionFilePropertyId);
+ IEnumerable GetAllByAcqPropertyId(long fileId, long propertyId);
IEnumerable GetAllByPropertyId(long propertyId);
- int GetCountByPropertyId(long propertyId);
+ PimsTake GetById(long takeId);
+
+ PimsTake AddTake(PimsTake take);
+
+ PimsTake UpdateTake(PimsTake take);
- void UpdateAcquisitionPropertyTakes(long acquisitionFilePropertyId, IEnumerable takes);
+ bool TryDeleteTake(long takeId);
+
+ int GetCountByPropertyId(long propertyId);
IEnumerable GetAllByPropertyAcquisitionFileId(long acquisitionFilePropertyId);
}
diff --git a/source/backend/dal/Repositories/TakeRepository.cs b/source/backend/dal/Repositories/TakeRepository.cs
index c82fe18a04..a9043a53a7 100644
--- a/source/backend/dal/Repositories/TakeRepository.cs
+++ b/source/backend/dal/Repositories/TakeRepository.cs
@@ -24,6 +24,24 @@ public TakeRepository(PimsContext dbContext, ClaimsPrincipal user, ILogger
+ /// Get take by id.
+ ///
+ ///
+ ///
+ public PimsTake GetById(long takeId)
+ {
+ return Context.PimsTakes
+
+ .Include(t => t.PropertyAcquisitionFile)
+ .Include(t => t.TakeSiteContamTypeCodeNavigation)
+ .Include(t => t.TakeStatusTypeCodeNavigation)
+ .Include(t => t.TakeTypeCodeNavigation)
+ .Include(t => t.LandActTypeCodeNavigation)
+ .AsNoTracking()
+ .FirstOrDefault(t => t.TakeId == takeId) ?? throw new KeyNotFoundException($"Unable to find take with id {takeId}");
+ }
+
///
/// Get all of the takes that are associated to a given acquisition file by its id.
///
@@ -46,9 +64,9 @@ public IEnumerable GetAllByAcquisitionFileId(long fileId)
/// Get all Takes for a Property in the Acquisition File.
///
///
- ///
+ ///
///
- public IEnumerable GetAllByAcqPropertyId(long fileId, long acquisitionFilePropertyId)
+ public IEnumerable GetAllByAcqPropertyId(long fileId, long propertyId)
{
return Context.PimsTakes
.Include(t => t.PropertyAcquisitionFile)
@@ -57,7 +75,7 @@ public IEnumerable GetAllByAcqPropertyId(long fileId, long acquisition
.Include(t => t.TakeTypeCodeNavigation)
.Include(t => t.LandActTypeCodeNavigation)
.Where(t => t.PropertyAcquisitionFile.AcquisitionFileId == fileId
- && t.PropertyAcquisitionFile.PropertyId == acquisitionFilePropertyId)
+ && t.PropertyAcquisitionFile.PropertyId == propertyId)
.AsNoTracking();
}
@@ -87,14 +105,44 @@ public int GetCountByPropertyId(long propertyId)
.Count();
}
+ public PimsTake AddTake(PimsTake take)
+ {
+ using var scope = Logger.QueryScope();
+
+ Context.PimsTakes.Add(take);
+
+ return take;
+ }
+
///
- /// Sets the passed list of takes as the takes associated to the given acquisition property, adding, deleting and updating as necessary.
+ /// Update the passed take.
///
- ///
- ///
- public void UpdateAcquisitionPropertyTakes(long acquisitionFilePropertyId, IEnumerable takes)
+ ///
+ public PimsTake UpdateTake(PimsTake take)
+ {
+ using var scope = Logger.QueryScope();
+
+ var existingTake = Context.PimsTakes.FirstOrDefault(x => x.TakeId == take.TakeId) ?? throw new KeyNotFoundException();
+
+ take.PropertyAcquisitionFileId = existingTake.PropertyAcquisitionFileId; // A take cannot be migrated between properties.
+ Context.Entry(existingTake).CurrentValues.SetValues(take);
+
+ return existingTake;
+ }
+
+ public bool TryDeleteTake(long takeId)
{
- Context.UpdateChild(p => p.PimsTakes, acquisitionFilePropertyId, takes.ToArray(), true);
+ using var scope = Logger.QueryScope();
+
+ var deletedEntity = Context.PimsTakes.Where(x => x.TakeId == takeId).FirstOrDefault();
+ if (deletedEntity is not null)
+ {
+ Context.PimsTakes.Remove(deletedEntity);
+
+ return true;
+ }
+
+ return false;
}
public IEnumerable GetAllByPropertyAcquisitionFileId(long acquisitionFilePropertyId)
diff --git a/source/backend/entities/Extensions/ExpiringTypeEntity.cs b/source/backend/entities/Extensions/ExpiringTypeEntity.cs
index 12109900ca..38ff5e763f 100644
--- a/source/backend/entities/Extensions/ExpiringTypeEntity.cs
+++ b/source/backend/entities/Extensions/ExpiringTypeEntity.cs
@@ -24,7 +24,7 @@ public static bool IsExpiredType(this IExpiringTypeEntity t
/// True if the type is expired; false otherwise.
public static bool IsExpiredType(this IExpiringTypeEntity type, DateTime? currentDate = null)
{
- DateOnly now = DateOnly.FromDateTime(currentDate.HasValue ? (DateTime)currentDate?.Date : DateTime.UtcNow.Date);
+ DateOnly now = DateOnly.FromDateTime(currentDate.HasValue ? (DateTime)currentDate?.Date : DateTime.Now.Date);
return (type.EffectiveDate > now) || (type.ExpiryDate.HasValue && type.ExpiryDate <= now);
}
}
diff --git a/source/backend/tests/core/Entities/TakeHelper.cs b/source/backend/tests/core/Entities/TakeHelper.cs
new file mode 100644
index 0000000000..9621a7e3cb
--- /dev/null
+++ b/source/backend/tests/core/Entities/TakeHelper.cs
@@ -0,0 +1,40 @@
+using Pims.Dal.Entities;
+using System;
+using Entity = Pims.Dal.Entities;
+
+namespace Pims.Core.Test
+{
+ ///
+ /// EntityHelper static class, provides helper methods to create test entities.
+ ///
+ public static partial class EntityHelper
+ {
+ ///
+ /// Create a new instance of a Take.
+ ///
+ ///
+ ///
+ public static Entity.PimsTake CreateTake(long id = 1)
+ {
+ return new Entity.PimsTake()
+ {
+ Internal_Id = id,
+ TakeId = id,
+ AppCreateTimestamp = DateTime.Now,
+ AppCreateUserid = "admin",
+ AppCreateUserDirectory = string.Empty,
+ AppLastUpdateUserDirectory = string.Empty,
+ AppLastUpdateUserid = string.Empty,
+ DbCreateUserid = string.Empty,
+ DbLastUpdateUserid = string.Empty,
+ ConcurrencyControlNumber = 1,
+ AreaUnitTypeCodeNavigation = new Entity.PimsAreaUnitType() { Id = id.ToString(), DbCreateUserid = "test", DbLastUpdateUserid = "test", AreaUnitTypeCode = "test", Description = "test" },
+ LandActTypeCodeNavigation = new Entity.PimsLandActType() { Id = id.ToString(), DbCreateUserid = "test", DbLastUpdateUserid = "test", LandActTypeCode = "test", Description = "test" },
+ TakeSiteContamTypeCodeNavigation = new PimsTakeSiteContamType() { Id = id.ToString(), DbCreateUserid = "test", DbLastUpdateUserid = "test", TakeSiteContamTypeCode = "test", Description = "test" },
+ TakeStatusTypeCodeNavigation = new PimsTakeStatusType() { Id = id.ToString(), DbCreateUserid = "test", DbLastUpdateUserid = "test", TakeStatusTypeCode = "test", Description = "test" },
+ TakeTypeCodeNavigation = new PimsTakeType() { Id = id.ToString(), DbCreateUserid = "test", DbLastUpdateUserid = "test", TakeTypeCode = "test", Description = "test" },
+ PropertyAcquisitionFile = new PimsPropertyAcquisitionFile(),
+ };
+ }
+ }
+}
diff --git a/source/backend/tests/unit/api/Controllers/Takes/TakeControllerTest.cs b/source/backend/tests/unit/api/Controllers/Takes/TakeControllerTest.cs
new file mode 100644
index 0000000000..55bafd40c6
--- /dev/null
+++ b/source/backend/tests/unit/api/Controllers/Takes/TakeControllerTest.cs
@@ -0,0 +1,221 @@
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using FluentAssertions;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+using Moq;
+using Pims.Api.Areas.Admin.Controllers;
+using Pims.Api.Areas.Takes.Controllers;
+using Pims.Api.Models.Concepts.Take;
+using Pims.Api.Models.Concepts;
+using Pims.Api.Services;
+using Pims.Core.Exceptions;
+using Pims.Core.Test;
+using Pims.Dal.Entities;
+using Pims.Dal.Security;
+using Xunit;
+using System;
+using Pims.Api.Helpers.Exceptions;
+using Pims.Dal.Exceptions;
+
+namespace Pims.Api.Test.Controllers
+{
+ [Trait("category", "unit")]
+ [Trait("category", "api")]
+ [Trait("area", "takes")]
+ [ExcludeFromCodeCoverage]
+ public class TakeControllerTest
+ {
+ // xUnit.net creates a new instance of the test class for every test that is run,
+ // so any code which is placed into the constructor of the test class will be run for every single test.
+ private readonly TestHelper _helper;
+ private readonly TakeController _controller;
+ private readonly Mock _service;
+ private readonly IMapper _mapper;
+
+ public TakeControllerTest()
+ {
+ this._helper = new TestHelper();
+ this._controller = this._helper.CreateController(Permissions.PropertyView, Permissions.AcquisitionFileView);
+ this._service = this._helper.GetService>();
+ this._mapper = this._helper.GetService();
+ }
+
+ [Fact]
+ public void GetTakesByAcquisitionFileId_Success()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetByFileId(It.IsAny()));
+
+ // Act
+ var result = this._controller.GetTakesByAcquisitionFileId(1);
+
+ // Assert
+ result.Should().BeOfType();
+ this._service.Verify(m => m.GetByFileId(It.IsAny()), Times.Once());
+ }
+
+ [Fact]
+ public void GetTakesByPropertyId_Success()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetByPropertyId(It.IsAny(), It.IsAny()));
+
+ // Act
+ var result = this._controller.GetTakesByPropertyId(1, 2);
+
+ // Assert
+ result.Should().BeOfType();
+ this._service.Verify(m => m.GetByPropertyId(It.IsAny(), It.IsAny()), Times.Once());
+ }
+
+ [Fact]
+ public void GetTakesCountByPropertyId_Success()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetCountByPropertyId(It.IsAny()));
+
+ // Act
+ var result = this._controller.GetTakesCountByPropertyId(1);
+
+ // Assert
+ result.Should().BeOfType();
+ this._service.Verify(m => m.GetCountByPropertyId(It.IsAny()), Times.Once());
+ }
+
+ [Fact]
+ public void GetTakeById_Success()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetById(It.IsAny())).Returns(new PimsTake() { PropertyAcquisitionFileId = 1 });
+
+ // Act
+ var result = this._controller.GetTakeByPropertyFileId(1, 1);
+
+ // Assert
+ result.Should().BeOfType();
+ this._service.Verify(m => m.GetById(It.IsAny()));
+ }
+
+ [Fact]
+ public void GetTakeById_InvalidId()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetById(It.IsAny())).Returns(new PimsTake() { PropertyAcquisitionFileId = 2 });
+
+ // Act
+ Action act = () => this._controller.GetTakeByPropertyFileId(1, 1);
+
+ // Assert
+ act.Should().Throw().WithMessage("Invalid acquisition file property id.");
+ }
+
+ [Fact]
+ public void UpdateTakeByPropertyId_InvalidFilePropertyId()
+ {
+ // Arrange
+ this._service.Setup(m => m.UpdateAcquisitionPropertyTake(It.IsAny(), It.IsAny()));
+
+ // Act
+ Action act = () => this._controller.UpdateAcquisitionPropertyTake(1, 1, new TakeModel() { Id = 1 });
+
+ // Assert
+ act.Should().Throw().WithMessage("Invalid acquisition file property id.");
+ }
+
+ [Fact]
+ public void UpdateTakeByPropertyId_InvalidTakeId()
+ {
+ // Arrange
+ this._service.Setup(m => m.UpdateAcquisitionPropertyTake(It.IsAny(), It.IsAny()));
+
+ // Act
+ Action act = () => this._controller.UpdateAcquisitionPropertyTake(1, 1, new TakeModel() { PropertyAcquisitionFileId = 1 });
+
+ // Assert
+ act.Should().Throw().WithMessage("Invalid take id.");
+ }
+
+ [Fact]
+ public void UpdateTakeByPropertyId_Success()
+ {
+ // Arrange
+ this._service.Setup(m => m.UpdateAcquisitionPropertyTake(It.IsAny(), It.IsAny()));
+
+ // Act
+ var result = this._controller.UpdateAcquisitionPropertyTake(1, 1, new TakeModel() { PropertyAcquisitionFileId = 1, Id = 1 });
+
+ // Assert
+ result.Should().BeOfType();
+ this._service.Verify(m => m.UpdateAcquisitionPropertyTake(It.IsAny(), It.IsAny()));
+ }
+
+ [Fact]
+ public void DeleteTakeByPropertyId_Invalid_AcquisitionFilePropertyId()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetById(It.IsAny())).Returns(new PimsTake() { PropertyAcquisitionFileId = 2 });
+
+ // Act
+ Action act = () => this._controller.DeleteAcquisitionPropertyTake(1, 1, new string[0]);
+
+ // Assert
+ act.Should().Throw().WithMessage("Invalid acquisition file property id.");
+ }
+
+ [Fact]
+ public void DeleteTakeByPropertyId_Failed_Delete()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetById(It.IsAny())).Returns(new PimsTake() { PropertyAcquisitionFileId = 1 });
+ this._service.Setup(m => m.DeleteAcquisitionPropertyTake(It.IsAny(), It.IsAny>())).Returns(false);
+
+ // Act
+ Action act = () => this._controller.DeleteAcquisitionPropertyTake(1, 1, new string[0]);
+
+ // Assert
+ act.Should().Throw().WithMessage("Failed to delete take 1.");
+ }
+
+ [Fact]
+ public void DeleteTakeByPropertyId_Success()
+ {
+ // Arrange
+ this._service.Setup(m => m.GetById(It.IsAny())).Returns(new PimsTake() { PropertyAcquisitionFileId = 1 });
+ this._service.Setup(m => m.DeleteAcquisitionPropertyTake(It.IsAny(), It.IsAny>())).Returns(true);
+
+ // Act
+ this._controller.DeleteAcquisitionPropertyTake(1, 1, new string[0]);
+
+ // Assert
+ this._service.Verify(m => m.DeleteAcquisitionPropertyTake(It.IsAny(), It.IsAny>()));
+ }
+
+ [Fact]
+ public void AddTakeByPropertyId_InvalidId()
+ {
+ // Arrange
+ this._service.Setup(m => m.AddAcquisitionPropertyTake(It.IsAny(), It.IsAny()));
+
+ // Act
+ Action act = () => this._controller.AddAcquisitionPropertyTake(1, new TakeModel());
+
+ // Assert
+ act.Should().Throw().WithMessage("Invalid acquisition file property id.");
+ }
+
+ [Fact]
+ public void AddTakeByPropertyId_Success()
+ {
+ // Arrange
+ this._service.Setup(m => m.AddAcquisitionPropertyTake(It.IsAny(), It.IsAny()));
+
+ // Act
+ var result = this._controller.AddAcquisitionPropertyTake(1, new TakeModel() { PropertyAcquisitionFileId = 1 });
+
+ // Assert
+ result.Should().BeOfType();
+ this._service.Verify(m => m.AddAcquisitionPropertyTake(It.IsAny(), It.IsAny()));
+ }
+ }
+}
diff --git a/source/backend/tests/unit/api/Controllers/Takes/TakesControllerTest.cs b/source/backend/tests/unit/api/Controllers/Takes/TakesControllerTest.cs
deleted file mode 100644
index 5767b9feb9..0000000000
--- a/source/backend/tests/unit/api/Controllers/Takes/TakesControllerTest.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using FluentAssertions;
-using MapsterMapper;
-using Microsoft.AspNetCore.Mvc;
-using Moq;
-using Pims.Api.Areas.Admin.Controllers;
-using Pims.Api.Areas.Takes.Controllers;
-using Pims.Api.Models.Concepts.Take;
-using Pims.Api.Models.Concepts;
-using Pims.Api.Services;
-using Pims.Core.Exceptions;
-using Pims.Core.Test;
-using Pims.Dal.Entities;
-using Pims.Dal.Security;
-using Xunit;
-
-namespace Pims.Api.Test.Controllers
-{
- [Trait("category", "unit")]
- [Trait("category", "api")]
- [Trait("area", "takes")]
- [ExcludeFromCodeCoverage]
- public class TakesControllerTest
- {
- // xUnit.net creates a new instance of the test class for every test that is run,
- // so any code which is placed into the constructor of the test class will be run for every single test.
- private readonly TestHelper _helper;
- private readonly TakeController _controller;
- private readonly Mock _service;
- private readonly IMapper _mapper;
-
- public TakesControllerTest()
- {
- this._helper = new TestHelper();
- this._controller = this._helper.CreateController(Permissions.PropertyView, Permissions.AcquisitionFileView);
- this._service = this._helper.GetService>();
- this._mapper = this._helper.GetService();
- }
-
- [Fact]
- public void GetTakesByAcquisitionFileId_Success()
- {
- // Arrange
- this._service.Setup(m => m.GetByFileId(It.IsAny()));
-
- // Act
- var result = this._controller.GetTakesByAcquisitionFileId(1);
-
- // Assert
- result.Should().BeOfType();
- this._service.Verify(m => m.GetByFileId(It.IsAny()), Times.Once());
- }
-
- [Fact]
- public void GetTakesByPropertyId_Success()
- {
- // Arrange
- this._service.Setup(m => m.GetByPropertyId(It.IsAny(), It.IsAny()));
-
- // Act
- var result = this._controller.GetTakesByPropertyId(1, 2);
-
- // Assert
- result.Should().BeOfType();
- this._service.Verify(m => m.GetByPropertyId(It.IsAny(), It.IsAny()), Times.Once());
- }
-
- [Fact]
- public void GetTakesCountByPropertyId_Success()
- {
- // Arrange
- this._service.Setup(m => m.GetCountByPropertyId(It.IsAny()));
-
- // Act
- var result = this._controller.GetTakesCountByPropertyId(1);
-
- // Assert
- result.Should().BeOfType();
- this._service.Verify(m => m.GetCountByPropertyId(It.IsAny()), Times.Once());
- }
-
- [Fact]
- public void UpdateAcquisitionPropertyTakes_Success()
- {
- // Arrange
- this._service.Setup(m => m.UpdateAcquisitionPropertyTakes(It.IsAny(), It.IsAny>()));
-
- // Act
- var result = this._controller.UpdateAcquisitionPropertyTakes(1, new List());
-
- // Assert
- result.Should().BeOfType();
- this._service.Verify(m => m.UpdateAcquisitionPropertyTakes(It.IsAny(), It.IsAny>()));
- }
- }
-}
diff --git a/source/backend/tests/unit/api/Services/TakeServiceTest.cs b/source/backend/tests/unit/api/Services/TakeServiceTest.cs
index b0f7233ed4..7e18042639 100644
--- a/source/backend/tests/unit/api/Services/TakeServiceTest.cs
+++ b/source/backend/tests/unit/api/Services/TakeServiceTest.cs
@@ -38,6 +38,34 @@ private TakeService CreateWithPermissions(params Permissions[] permissions)
return this._helper.Create(user);
}
+ [Fact]
+ public void GetById_Success()
+ {
+ // Arrange
+ var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView);
+ var repo = this._helper.GetService>();
+ repo.Setup(x => x.GetById(It.IsAny()));
+
+ // Act
+ var result = service.GetById(1);
+
+ // Assert
+ repo.Verify(x => x.GetById(It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ public void GetById_NoPermission()
+ {
+ // Arrange
+ var service = this.CreateWithPermissions();
+
+ // Act
+ Action act = () => service.GetById(1);
+
+ // Assert
+ act.Should().Throw();
+ }
+
[Fact]
public void GetByFileId_Success()
{
@@ -124,13 +152,13 @@ public void GetCountByPropertyId_NoPermission()
}
[Fact]
- public void Update_Success()
+ public void Add_Success()
{
// Arrange
var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView);
var takeRepository = this._helper.GetService>();
takeRepository.Setup(x =>
- x.UpdateAcquisitionPropertyTakes(It.IsAny(), It.IsAny>()));
+ x.AddTake(It.IsAny()));
var acqRepository = this._helper.GetService>();
acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(new PimsAcquisitionFile() { AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString() });
@@ -140,20 +168,231 @@ public void Update_Success()
solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(true);
// Act
- var result = service.UpdateAcquisitionPropertyTakes(1, new List());
+ var result = service.AddAcquisitionPropertyTake(1, new PimsTake());
+
+ // Assert
+ takeRepository.Verify(x => x.AddTake(It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ public void Add_NoPermission()
+ {
+ // Arrange
+ var service = this.CreateWithPermissions();
+
+ // Act
+ Action act = () => service.AddAcquisitionPropertyTake(1, new PimsTake());
// Assert
- takeRepository.Verify(x => x.UpdateAcquisitionPropertyTakes(1, new List()), Times.Once);
+ act.Should().Throw();
}
[Fact]
- public void Update_TakeComplete_No_Date()
+ public void Add_InvalidStatus_AcquisitionFile_Complete()
{
// Arrange
var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView);
var takeRepository = this._helper.GetService>();
takeRepository.Setup(x =>
- x.UpdateAcquisitionPropertyTakes(It.IsAny(), It.IsAny>()));
+ x.AddTake(It.IsAny()));
+
+ var acqRepository = this._helper.GetService>();
+ acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(new PimsAcquisitionFile() { AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString() });
+
+ var solver = this._helper.GetService>();
+ solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(false);
+
+ // Act
+ Action act = () => service.AddAcquisitionPropertyTake(1, new PimsTake());
+
+ // Assert
+ act.Should().Throw().WithMessage("Retired records are referenced for historical purposes only and cannot be edited or deleted. If the take has been added in error, contact your system administrator to re-open the file, which will allow take deletion.");
+ }
+
+ [Fact]
+ public void Add_CompleteTake_No_Date()
+ {
+ // Arrange
+ var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView);
+
+ var acqRepository = this._helper.GetService>();
+ acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(
+ new PimsAcquisitionFile()
+ {
+ AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString()
+ }
+ );
+
+ PimsTake completedTake = new()
+ {
+ TakeId = 100,
+ TakeStatusTypeCode = AcquisitionTakeStatusTypes.COMPLETE.ToString(),
+ };
+
+ var takeRepository = this._helper.GetService>();
+ takeRepository.Setup(x => x.GetAllByPropertyAcquisitionFileId(It.IsAny())).Returns(
+ new List() { completedTake }
+ );
+
+ var solver = this._helper.GetService>();
+ solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(true);
+
+ // Act
+ Action act = () => service.AddAcquisitionPropertyTake(1, completedTake);
+
+ // Assert
+ act.Should().Throw().WithMessage("A completed take must have a completion date.");
+ }
+
+ [Fact]
+ public void Add_CompleteTake_LandActType_No_EndDt()
+ {
+ // Arrange
+ var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView);
+
+ var acqRepository = this._helper.GetService>();
+ acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(
+ new PimsAcquisitionFile()
+ {
+ AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString()
+ }
+ );
+
+ PimsTake completedTake = new()
+ {
+ TakeId = 100,
+ CompletionDt = DateOnly.FromDateTime(DateTime.Now),
+ TakeStatusTypeCode = AcquisitionTakeStatusTypes.COMPLETE.ToString(),
+ IsNewLandAct = true,
+ LandActTypeCode = LandActTypes.TRANSFER_OF_ADMIN_AND_CONTROL.ToString(),
+ LandActEndDt = DateOnly.FromDateTime(DateTime.Now),
+ };
+
+ var takeRepository = this._helper.GetService>();
+ takeRepository.Setup(x => x.GetAllByPropertyAcquisitionFileId(It.IsAny())).Returns(
+ new List() { completedTake }
+ );
+
+ var solver = this._helper.GetService>();
+ solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(true);
+
+ // Act
+ Action act = () => service.AddAcquisitionPropertyTake(1, completedTake);
+
+ // Assert
+ act.Should().Throw().WithMessage("'Crown Grant' and 'Transfer' Land Acts cannot have an end date.");
+ }
+
+ [Fact]
+ public void Add_AcquisitionFile_Active_Update_CompleteTake_Admin_Success()
+ {
+ // Arrange
+ var service = this.CreateWithPermissions(Permissions.SystemAdmin, Permissions.PropertyView, Permissions.AcquisitionFileView);
+
+ var acqRepository = this._helper.GetService>();
+ acqRepository.Setup(x => x.GetProperty(It.IsAny())).Returns(new PimsProperty() { PropertyId = 1 });
+ acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(new PimsAcquisitionFile() { AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString() });
+
+ PimsTake completedTake = new()
+ {
+ TakeId = 100,
+ TakeStatusTypeCode = AcquisitionTakeStatusTypes.COMPLETE.ToString(),
+ };
+
+ var takeRepository = this._helper.GetService>();
+ takeRepository.Setup(x => x.GetAllByPropertyId(It.IsAny())).Returns(new List() { completedTake });
+ takeRepository.Setup(x => x.UpdateTake(It.IsAny())).Returns(completedTake);
+
+ var solver = this._helper.GetService>();
+ solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(true);
+
+ // Act
+ var result = service.AddAcquisitionPropertyTake(1, new PimsTake());
+
+ // Assert
+ takeRepository.Verify(x => x.AddTake(It.IsAny()), Times.Once);
+ }
+
+ [Fact]
+ public void Add_AcquisitionFile_Active_Update_CompleteTake_Error()
+ {
+ // Arrange
+ var service = this.CreateWithPermissions(Permissions.PropertyView, Permissions.AcquisitionFileView);
+
+ var acqRepository = this._helper.GetService>();
+ acqRepository.Setup(x => x.GetProperty(It.IsAny())).Returns(new PimsProperty() { PropertyId = 1 });
+ acqRepository.Setup(x => x.GetByAcquisitionFilePropertyId(It.IsAny())).Returns(new PimsAcquisitionFile() { AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString() });
+
+ PimsTake completedTake = new()
+ {
+ TakeId = 100,
+ TakeStatusTypeCode = AcquisitionTakeStatusTypes.COMPLETE.ToString(),
+ };
+
+ var takeRepository = this._helper.GetService>();
+ takeRepository.Setup(x => x.GetAllByPropertyId(It.IsAny())).Returns(new List() { completedTake });
+ takeRepository.Setup(x => x.GetAllByPropertyAcquisitionFileId(It.IsAny())).Returns(new List() { completedTake });
+ takeRepository.Setup(x => x.UpdateTake(It.IsAny())).Returns(completedTake);
+
+ var solver = this._helper.GetService>();
+ solver.Setup(x => x.CanEditTakes(It.IsAny())).Returns(true);
+
+ // Act
+ Action act = () => service.AddAcquisitionPropertyTake(1, new PimsTake() { TakeId = 100 });
+
+ // Assert
+ act.Should().Throw();
+ }
+
+ public static IEnumerable