Skip to content

Commit

Permalink
Merge pull request #3907 from asanchezr/release/uat_is76
Browse files Browse the repository at this point in the history
UAT Release - IS76
  • Loading branch information
asanchezr authored Mar 28, 2024
2 parents 2d00825 + 43b6338 commit 363406d
Show file tree
Hide file tree
Showing 340 changed files with 6,485 additions and 2,139 deletions.
6 changes: 3 additions & 3 deletions source/backend/api/Pims.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<UserSecretsId>0ef6255f-9ea0-49ec-8c65-c172304b4926</UserSecretsId>
<Version>5.0.1-75.35</Version>
<Version>5.0.1-75.35</Version>
<AssemblyVersion>5.0.1.75</AssemblyVersion>
<Version>5.0.1-76.36</Version>
<Version>5.0.1-76.36</Version>
<AssemblyVersion>5.0.1.76</AssemblyVersion>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<ProjectGuid>16BC0468-78F6-4C91-87DA-7403C919E646</ProjectGuid>
<TargetFramework>net8.0</TargetFramework>
Expand Down
48 changes: 42 additions & 6 deletions source/backend/api/Services/AcquisitionFileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,14 +227,15 @@ public PimsAcquisitionFile Add(PimsAcquisitionFile acquisitionFile, IEnumerable<
ValidateStaff(acquisitionFile);
ValidateOrganizationStaff(acquisitionFile);

acquisitionFile.AcquisitionFileStatusTypeCode = "ACTIVE";
MatchProperties(acquisitionFile, userOverrides);
ValidatePropertyRegions(acquisitionFile);

PopulateAcquisitionChecklist(acquisitionFile);

acquisitionFile.AcquisitionFileStatusTypeCode = AcquisitionStatusTypes.ACTIVE.ToString();
var newAcqFile = _acqFileRepository.Add(acquisitionFile);
_acqFileRepository.CommitTransaction();

return newAcqFile;
}

Expand Down Expand Up @@ -625,7 +626,12 @@ private void MatchProperties(PimsAcquisitionFile acquisitionFile, IEnumerable<Us
var pid = acquisitionProperty.Property.Pid.Value;
try
{
var foundProperty = _propertyRepository.GetByPid(pid);
var foundProperty = _propertyRepository.GetByPid(pid, true);
if (foundProperty.IsRetired.HasValue && foundProperty.IsRetired.Value)
{
throw new BusinessRuleViolationException("Retired property can not be selected.");
}

acquisitionProperty.PropertyId = foundProperty.Internal_Id;
_propertyService.UpdateLocation(acquisitionProperty.Property, ref foundProperty, userOverrideCodes);
acquisitionProperty.Property = foundProperty;
Expand All @@ -641,7 +647,12 @@ private void MatchProperties(PimsAcquisitionFile acquisitionFile, IEnumerable<Us
var pin = acquisitionProperty.Property.Pin.Value;
try
{
var foundProperty = _propertyRepository.GetByPin(pin);
var foundProperty = _propertyRepository.GetByPin(pin, true);
if (foundProperty.IsRetired.HasValue && foundProperty.IsRetired.Value)
{
throw new BusinessRuleViolationException("Retired property can not be selected.");
}

acquisitionProperty.PropertyId = foundProperty.Internal_Id;
_propertyService.UpdateLocation(acquisitionProperty.Property, ref foundProperty, userOverrideCodes);
acquisitionProperty.Property = foundProperty;
Expand Down Expand Up @@ -745,10 +756,10 @@ private void TransferPropertiesOfInterest(PimsAcquisitionFile acquisitionFile, b
{
// Get the current properties in the research file
var currentProperties = _acquisitionFilePropertyRepository.GetPropertiesByAcquisitionFileId(acquisitionFile.Internal_Id);
var propertiesOfInterest = currentProperties.Where(p => p.Property.IsPropertyOfInterest);

// PSP-6111 Business rule: Transfer properties of interest to core inventory when acquisition file is completed
foreach (var acquisitionProperty in propertiesOfInterest)
// PSP-7892 Business rule: Process all properties in the acq file (not only properties of interest).
foreach (var acquisitionProperty in currentProperties)
{
var property = acquisitionProperty.Property;
var takes = _takeRepository.GetAllByPropertyAcquisitionFileId(acquisitionProperty.Internal_Id);
Expand Down Expand Up @@ -776,11 +787,36 @@ private void TransferPropertiesOfInterest(PimsAcquisitionFile acquisitionFile, b
isOtherInterest = false;
}

if (!userOverride && (isOwned || isOtherInterest))
// PSP-7892: Follow ownership priority when updating an existing property
if (property.IsOwned || isOwned)
{
isOwned = true;
isOtherInterest = false;
isPropertyOfInterest = false;
}
else if (property.IsOtherInterest || isOtherInterest)
{
isOwned = false;
isOtherInterest = true;
isPropertyOfInterest = false;
}
else if (property.IsPropertyOfInterest || isPropertyOfInterest)
{
isOwned = false;
isOtherInterest = false;
isPropertyOfInterest = true;
}

if (!userOverride && property.IsPropertyOfInterest && (isOwned || isOtherInterest))
{
throw new UserOverrideException(UserOverrideCode.PoiToInventory, "You have one or more take(s) that will be added to MoTI Inventory. Do you want to acknowledge and proceed?");
}

if (!userOverride && property.IsOtherInterest && isOwned)
{
throw new UserOverrideException(UserOverrideCode.PoiToInventory, "You have one or more take(s) that will be changed from 'Other Interest' to 'Core Inventory'. Do you want to acknowledge and proceed?");
}

PropertyOwnershipState ownership = new() { isOwned = isOwned, isPropertyOfInterest = isPropertyOfInterest, isOtherInterest = isOtherInterest, isDisposed = false };
_propertyRepository.TransferFileProperty(property, ownership);
}
Expand Down
115 changes: 72 additions & 43 deletions source/backend/api/Services/DispositionFileService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Globalization;
using System.Linq;
using System.Security.Claims;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pims.Api.Constants;
Expand Down Expand Up @@ -74,11 +73,9 @@ public PimsDispositionFile Add(PimsDispositionFile dispositionFile, IEnumerable<

dispositionFile.DispositionStatusTypeCode ??= EnumDispositionStatusTypeCode.UNKNOWN.ToString();
dispositionFile.DispositionFileStatusTypeCode ??= EnumDispositionFileStatusTypeCode.ACTIVE.ToString();

ValidateStaff(dispositionFile);

MatchProperties(dispositionFile, userOverrides);

ValidatePropertyRegions(dispositionFile);

var newDispositionFile = _dispositionFileRepository.Add(dispositionFile);
Expand Down Expand Up @@ -117,35 +114,18 @@ public PimsDispositionFile Update(long id, PimsDispositionFile dispositionFile,
throw new BusinessRuleViolationException("The file you are editing is not active or draft, so you cannot save changes. Refresh your browser to see file state.");
}

ValidateStaff(dispositionFile);
ValidateVersion(id, dispositionFile.ConcurrencyControlNumber);

dispositionFile.ThrowContractorRemovedFromTeam(_user, _userRepository);

var doNotAddToStatuses = new List<string>() { EnumDispositionFileStatusTypeCode.COMPLETE.ToString(), EnumDispositionFileStatusTypeCode.ARCHIVED.ToString(), EnumDispositionFileStatusTypeCode.CANCELLED.ToString(), };
// validate disposition file state before proceeding with any database updates
var currentDispositionFile = _dispositionFileRepository.GetById(id);
ValidateFileBeforeUpdate(dispositionFile, currentDispositionFile, userOverrides);

if (!userOverrides.Contains(UserOverrideCode.DispositionFileFinalStatus) && !doNotAddToStatuses.Contains(currentDispositionFile.DispositionFileStatusTypeCode)
&& doNotAddToStatuses.Contains(dispositionFile.DispositionFileStatusTypeCode))
{
throw new UserOverrideException(UserOverrideCode.DispositionFileFinalStatus, "You are changing this file to a non-editable state. (Only system administrators can edit the file when set to Archived, Cancelled or Completed state). Do you wish to continue?");
}
else if (currentDispositionFile.DispositionFileStatusTypeCode != EnumDispositionFileStatusTypeCode.COMPLETE.ToString()
&& dispositionFile.DispositionFileStatusTypeCode == EnumDispositionFileStatusTypeCode.COMPLETE.ToString())
{
if (currentDispositionFile?.PimsDispositionSales?.FirstOrDefault()?.SaleFinalAmt == null)
{
throw new BusinessRuleViolationException("You have not added a Sales Price. Please add a Sales Price before completion.");
}
else if (currentDispositionFile.PimsDispositionFileProperties.Count > 0)
{
DisposeOfProperties(dispositionFile, userOverrides);
}
}
var isFileClosing = currentDispositionFile.DispositionFileStatusTypeCode != EnumDispositionFileStatusTypeCode.COMPLETE.ToString() &&
dispositionFile.DispositionFileStatusTypeCode == EnumDispositionFileStatusTypeCode.COMPLETE.ToString();

if (!userOverrides.Contains(UserOverrideCode.UpdateRegion))
if (isFileClosing && currentDispositionFile.PimsDispositionFileProperties?.Count > 0)
{
ValidateMinistryRegion(id, dispositionFile.RegionCode);
DisposeOfProperties(dispositionFile);
}

_dispositionFileRepository.Update(id, dispositionFile);
Expand Down Expand Up @@ -560,30 +540,69 @@ public PimsDispositionFile UpdateProperties(PimsDispositionFile dispositionFile,
return _dispositionFileRepository.GetById(dispositionFile.Internal_Id);
}

/// <summary>
/// Attempt to dispose of any properties if all business rules are met.
/// </summary>
/// <param name="dispositionFile"></param>
private void DisposeOfProperties(PimsDispositionFile dispositionFile, IEnumerable<UserOverrideCode> userOverrides)
private void ValidateFileBeforeUpdate(PimsDispositionFile incomingDispositionFile, PimsDispositionFile currentDispositionFile, IEnumerable<UserOverrideCode> userOverrides)
{
var currentProperties = _dispositionFilePropertyRepository.GetPropertiesByDispositionFileId(dispositionFile.Internal_Id);
if (currentProperties.Any(p => p.Property.IsOwned) && !userOverrides.Contains(UserOverrideCode.DisposeOfProperties))
// Implement file validation logic before proceeding to update. This includes file closing validation.
// The order of validation checks is important as it has been requested by business users.
var isFileClosing = currentDispositionFile.DispositionFileStatusTypeCode != EnumDispositionFileStatusTypeCode.COMPLETE.ToString() &&
incomingDispositionFile.DispositionFileStatusTypeCode == EnumDispositionFileStatusTypeCode.COMPLETE.ToString();

var currentProperties = _dispositionFilePropertyRepository.GetPropertiesByDispositionFileId(incomingDispositionFile.Internal_Id);

// The following checks result in hard STOP errors
if (isFileClosing)
{
throw new UserOverrideException(UserOverrideCode.DisposeOfProperties, "You are completing this Disposition File with owned PIMS inventory properties. All properties will be removed from the PIMS inventory (any Other Interests will remain). Do you wish to proceed?");
if (currentProperties.Any(p => !p.Property.IsOwned))
{
throw new BusinessRuleViolationException("You have one or more properties attached to this Disposition file that is NOT in the \"Core Inventory\" (i.e. owned by BCTFA and/or HMK). To complete this file you must either, remove these non \"Non-Core Inventory\" properties, OR make sure the property is added to the PIMS inventory first.");
}

if (currentDispositionFile.PimsDispositionSales?.FirstOrDefault()?.SaleFinalAmt == null)
{
throw new BusinessRuleViolationException("You have not added a Sales Price. Please add a Sales Price before completion.");
}
}
else if (currentProperties.Any(p => p.Property.IsPropertyOfInterest))

ValidateStaff(incomingDispositionFile);
incomingDispositionFile.ThrowContractorRemovedFromTeam(_user, _userRepository);

// From here on - these checks result in warnings that require user confirmation
if (!userOverrides.Contains(UserOverrideCode.UpdateRegion))
{
throw new BusinessRuleViolationException("You have one or more properties attached to this Disposition file that is NOT in the \"Core Inventory\" (i.e. owned by BCTFA and/or HMK). To complete this file you must either, remove these non \"Non-Core Inventory\" properties, OR make sure the property is added to the PIMS inventory first.");
// confirm user action - file region was changed
ValidateMinistryRegion(incomingDispositionFile.Internal_Id, incomingDispositionFile.RegionCode);
}

// Get the current properties in the research file
var nonEditableStatuses = new List<string>() { EnumDispositionFileStatusTypeCode.COMPLETE.ToString(), EnumDispositionFileStatusTypeCode.ARCHIVED.ToString(), EnumDispositionFileStatusTypeCode.CANCELLED.ToString(), };
var isFileChangingToNonEditableState = !nonEditableStatuses.Contains(currentDispositionFile.DispositionFileStatusTypeCode) && nonEditableStatuses.Contains(incomingDispositionFile.DispositionFileStatusTypeCode);

// confirm user action - file is changing to non-editable state
if (!userOverrides.Contains(UserOverrideCode.DispositionFileFinalStatus) && isFileChangingToNonEditableState)
{
throw new UserOverrideException(UserOverrideCode.DispositionFileFinalStatus, "You are changing this file to a non-editable state. (Only system administrators can edit the file when set to Archived, Cancelled or Completed state). Do you wish to continue?");
}

if (isFileClosing && !userOverrides.Contains(UserOverrideCode.DisposeOfProperties))
{
throw new UserOverrideException(UserOverrideCode.DisposeOfProperties, "You are completing this Disposition File with owned PIMS inventory properties. All properties will be removed from the PIMS inventory (any Other Interests will remain). Do you wish to proceed?");
}
}

/// <summary>
/// Attempt to dispose of any properties if all business rules are met.
/// </summary>
/// <param name="dispositionFile">The disposition file entity.</param>
private void DisposeOfProperties(PimsDispositionFile dispositionFile)
{
// Get the current properties in the disposition file
var currentProperties = _dispositionFilePropertyRepository.GetPropertiesByDispositionFileId(dispositionFile.Internal_Id);
var ownedProperties = currentProperties.Where(p => p.Property.IsOwned);

// PSP-7275 Business rule: Transfer properties of interest to disposed when disposition file is completed
foreach (var dispositionProperty in ownedProperties)
{
var property = dispositionProperty.Property;
_propertyRepository.TransferFileProperty(property, new Dal.Models.PropertyOwnershipState() { isDisposed = true, isPropertyOfInterest = false, isOtherInterest = false, isOwned = false});
_propertyRepository.TransferFileProperty(property, new Dal.Models.PropertyOwnershipState() { isDisposed = true, isPropertyOfInterest = false, isOtherInterest = false, isOwned = false });
}
}

Expand Down Expand Up @@ -683,10 +702,15 @@ private void MatchProperties(PimsDispositionFile dispositionFile, IEnumerable<Us
var pid = dispProperty.Property.Pid.Value;
try
{
var foundProperty = _propertyRepository.GetByPid(pid);
var foundProperty = _propertyRepository.GetByPid(pid, true);
if (foundProperty.IsRetired.HasValue && foundProperty.IsRetired.Value)
{
throw new BusinessRuleViolationException("Retired property can not be selected.");
}

dispProperty.PropertyId = foundProperty.Internal_Id;
_propertyService.UpdateLocation(dispProperty.Property, ref foundProperty, overrideCodes);
dispProperty.Property = null;
dispProperty.Property = foundProperty;
}
catch (KeyNotFoundException)
{
Expand All @@ -697,7 +721,7 @@ private void MatchProperties(PimsDispositionFile dispositionFile, IEnumerable<Us
}
else
{
throw new UserOverrideException(UserOverrideCode.DisposingPropertyNotInventoried, "You have added one or more properties to the disposition file that are not in the MoTI Inventory. Do you want to proceed?");
throw new UserOverrideException(UserOverrideCode.DisposingPropertyNotInventoried, "You have added one or more properties to the disposition file that are not in the MOTI Inventory. Do you want to proceed?");
}
}
}
Expand All @@ -706,10 +730,15 @@ private void MatchProperties(PimsDispositionFile dispositionFile, IEnumerable<Us
var pin = dispProperty.Property.Pin.Value;
try
{
var foundProperty = _propertyRepository.GetByPin(pin);
var foundProperty = _propertyRepository.GetByPin(pin, true);
if (foundProperty.IsRetired.HasValue && foundProperty.IsRetired.Value)
{
throw new BusinessRuleViolationException("Retired property can not be selected.");
}

dispProperty.PropertyId = foundProperty.Internal_Id;
_propertyService.UpdateLocation(dispProperty.Property, ref foundProperty, overrideCodes);
dispProperty.Property = null;
dispProperty.Property = foundProperty;
}
catch (KeyNotFoundException)
{
Expand Down
Loading

0 comments on commit 363406d

Please sign in to comment.