-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added check status logic when updating acq and related entities | psp-7006 #3602
Changes from all commits
5b8aec9
ab1b02c
8fe12ba
7c73745
ef23d36
023085f
96ee3af
c4eb179
3a9a4eb
a117b77
294c885
f16a01c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
using System.Runtime.Serialization; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Pims.Api.Constants | ||
{ | ||
[JsonConverter(typeof(JsonStringEnumMemberConverter))] | ||
public enum AcquisitionStatusTypes | ||
{ | ||
|
||
[EnumMember(Value = "ACTIVE")] | ||
ACTIVE, | ||
|
||
[EnumMember(Value = "ARCHIV")] | ||
ARCHIV, | ||
|
||
[EnumMember(Value = "CANCEL")] | ||
CANCEL, | ||
|
||
[EnumMember(Value = "CLOSED")] | ||
CLOSED, | ||
|
||
[EnumMember(Value = "COMPLT")] | ||
COMPLT, | ||
|
||
[EnumMember(Value = "DRAFT")] | ||
DRAFT, | ||
|
||
[EnumMember(Value = "HOLD")] | ||
HOLD, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System.Runtime.Serialization; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Pims.Api.Constants | ||
{ | ||
[JsonConverter(typeof(JsonStringEnumMemberConverter))] | ||
public enum AgreementStatusTypes | ||
{ | ||
[EnumMember(Value = "CANCELLED")] | ||
CANCELLED, | ||
|
||
[EnumMember(Value = "DRAFT")] | ||
DRAFT, | ||
|
||
[EnumMember(Value = "FINAL")] | ||
FINAL, | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
using System.Security.Claims; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Logging; | ||
using Pims.Api.Constants; | ||
using Pims.Api.Helpers.Exceptions; | ||
using Pims.Api.Helpers.Extensions; | ||
using Pims.Core.Exceptions; | ||
|
@@ -40,6 +41,7 @@ | |
private readonly ICompReqFinancialService _compReqFinancialService; | ||
private readonly IExpropriationPaymentRepository _expropriationPaymentRepository; | ||
private readonly ITakeRepository _takeRepository; | ||
private readonly IAcquisitionStatusSolver _statusSolver; | ||
|
||
public AcquisitionFileService( | ||
ClaimsPrincipal user, | ||
|
@@ -57,7 +59,8 @@ | |
IInterestHolderRepository interestHolderRepository, | ||
ICompReqFinancialService compReqFinancialService, | ||
IExpropriationPaymentRepository expropriationPaymentRepository, | ||
ITakeRepository takeRepository) | ||
ITakeRepository takeRepository, | ||
IAcquisitionStatusSolver statusSolver) | ||
{ | ||
_user = user; | ||
_logger = logger; | ||
|
@@ -75,6 +78,7 @@ | |
_compReqFinancialService = compReqFinancialService; | ||
_expropriationPaymentRepository = expropriationPaymentRepository; | ||
_takeRepository = takeRepository; | ||
_statusSolver = statusSolver; | ||
} | ||
|
||
public Paged<PimsAcquisitionFile> GetPage(AcquisitionFilter filter) | ||
|
@@ -240,6 +244,12 @@ | |
ValidateVersion(acquisitionFile.Internal_Id, acquisitionFile.ConcurrencyControlNumber); | ||
ValidateDrafts(acquisitionFile.Internal_Id); | ||
|
||
AcquisitionStatusTypes? currentAcquisitionStatus = GetCurrentAcquisitionStatus(acquisitionFile.Internal_Id); | ||
if (!_statusSolver.CanEditDetails(currentAcquisitionStatus) && !_user.HasPermission(Permissions.SystemAdmin)) | ||
{ | ||
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."); | ||
} | ||
|
||
if (!userOverrides.Contains(UserOverrideCode.UpdateRegion)) | ||
{ | ||
ValidateMinistryRegion(acquisitionFile.Internal_Id, acquisitionFile.RegionCode); | ||
|
@@ -341,6 +351,12 @@ | |
_user.ThrowIfNotAuthorized(Permissions.AcquisitionFileEdit); | ||
_user.ThrowInvalidAccessToAcquisitionFile(_userRepository, _acqFileRepository, acquisitionFile.Internal_Id); | ||
|
||
var currentAcquisitionStatus = GetCurrentAcquisitionStatus(acquisitionFile.Internal_Id); | ||
if (!_statusSolver.CanEditChecklists(currentAcquisitionStatus) && !_user.HasPermission(Permissions.SystemAdmin)) | ||
{ | ||
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."); | ||
} | ||
|
||
// Get the current checklist items for this acquisition file. | ||
var currentItems = _checklistRepository.GetAllChecklistItemsByAcquisitionFileId(acquisitionFile.Internal_Id).ToDictionary(ci => ci.Internal_Id); | ||
|
||
|
@@ -372,7 +388,7 @@ | |
_user.ThrowIfNotAuthorized(Permissions.AgreementView); | ||
_user.ThrowInvalidAccessToAcquisitionFile(_userRepository, _acqFileRepository, id); | ||
|
||
return _agreementRepository.GetAgreementsByAquisitionFile(id); | ||
return _agreementRepository.GetAgreementsByAcquisitionFile(id); | ||
} | ||
|
||
public IEnumerable<PimsAgreement> SearchAgreements(AcquisitionReportFilterModel filter) | ||
|
@@ -393,6 +409,31 @@ | |
{ | ||
_user.ThrowInvalidAccessToAcquisitionFile(_userRepository, _acqFileRepository, acquisitionFileId); | ||
|
||
var currentAcquisitionStatus = GetCurrentAcquisitionStatus(acquisitionFileId); | ||
|
||
var currentAgreements = _agreementRepository.GetAgreementsByAcquisitionFile(acquisitionFileId); | ||
|
||
var toBeUpdated = currentAgreements.Where(ca => agreements.Any(na => ca.AgreementId == na.AgreementId && !ca.IsEqual(na))); | ||
var toBeDeleted = currentAgreements.Where(ca => !agreements.Any(na => ca.AgreementId == na.AgreementId)); | ||
|
||
foreach (var agreement in toBeUpdated) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there a reason that agreements being edited and agreements being deleted are being split out into their own loops? Seems like the business logic that is being executed is identical, sort of adds an implication that updates should not be handles the same as deletes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although true, doing the loop on each would be the same as doing the loop on an aggregated collection. |
||
{ | ||
var agreementStatus = Enum.Parse<AgreementStatusTypes>(agreement.AgreementStatusTypeCode); | ||
if (!_statusSolver.CanEditOrDeleteAgreement(currentAcquisitionStatus, agreementStatus) && !_user.HasPermission(Permissions.SystemAdmin)) | ||
{ | ||
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."); | ||
} | ||
} | ||
|
||
foreach (var agreement in toBeDeleted) | ||
{ | ||
var agreementStatus = Enum.Parse<AgreementStatusTypes>(agreement.AgreementStatusTypeCode); | ||
if (!_statusSolver.CanEditOrDeleteAgreement(currentAcquisitionStatus, agreementStatus) && !_user.HasPermission(Permissions.SystemAdmin)) | ||
{ | ||
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."); | ||
} | ||
} | ||
|
||
var updatedAgreements = _agreementRepository.UpdateAllForAcquisition(acquisitionFileId, agreements); | ||
_agreementRepository.CommitTransaction(); | ||
|
||
|
@@ -414,6 +455,12 @@ | |
_user.ThrowIfNotAuthorized(Permissions.AcquisitionFileEdit); | ||
_user.ThrowInvalidAccessToAcquisitionFile(_userRepository, _acqFileRepository, acquisitionFileId); | ||
|
||
var currentAcquisitionStatus = GetCurrentAcquisitionStatus(acquisitionFileId); | ||
if (!_statusSolver.CanEditStakeholders(currentAcquisitionStatus) && !_user.HasPermission(Permissions.SystemAdmin)) | ||
{ | ||
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."); | ||
} | ||
|
||
var currentInterestHolders = _interestHolderRepository.GetInterestHoldersByAcquisitionFile(acquisitionFileId); | ||
|
||
// Verify that the interest holder is still the same (person or org) | ||
|
@@ -690,7 +737,7 @@ | |
|
||
private void ValidateDrafts(long acqFileId) | ||
{ | ||
var agreements = _agreementRepository.GetAgreementsByAquisitionFile(acqFileId); | ||
var agreements = _agreementRepository.GetAgreementsByAcquisitionFile(acqFileId); | ||
var compensations = _compensationRequisitionRepository.GetAllByAcquisitionFileId(acqFileId); | ||
if (agreements.Any(a => a?.AgreementStatusTypeCode == "DRAFT" || compensations.Any(c => c.IsDraft.HasValue && c.IsDraft.Value))) | ||
{ | ||
|
@@ -838,7 +885,7 @@ | |
|
||
private void ValidatePayeeDependency(PimsAcquisitionFile acquisitionFile) | ||
{ | ||
var currentAquisitionFile = _acqFileRepository.GetById(acquisitionFile.Internal_Id); | ||
var currentAcquisitionFile = _acqFileRepository.GetById(acquisitionFile.Internal_Id); | ||
var compensationRequisitions = _compensationRequisitionRepository.GetAllByAcquisitionFileId(acquisitionFile.Internal_Id); | ||
|
||
if (compensationRequisitions.Count == 0) | ||
|
@@ -851,23 +898,23 @@ | |
// Check for Acquisition File Owner removed | ||
if (compReq.AcquisitionOwnerId is not null | ||
&& !acquisitionFile.PimsAcquisitionOwners.Any(x => x.Internal_Id.Equals(compReq.AcquisitionOwnerId)) | ||
&& currentAquisitionFile.PimsAcquisitionOwners.Any(x => x.Internal_Id.Equals(compReq.AcquisitionOwnerId))) | ||
&& currentAcquisitionFile.PimsAcquisitionOwners.Any(x => x.Internal_Id.Equals(compReq.AcquisitionOwnerId))) | ||
{ | ||
throw new ForeignKeyDependencyException("Acquisition File Owner can not be removed since it's assigned as a payee for a compensation requisition"); | ||
} | ||
|
||
// Check for Acquisition InterestHolders | ||
if (compReq.InterestHolderId is not null | ||
&& !acquisitionFile.PimsInterestHolders.Any(x => x.Internal_Id.Equals(compReq.InterestHolderId)) | ||
&& currentAquisitionFile.PimsInterestHolders.Any(x => x.Internal_Id.Equals(compReq.InterestHolderId))) | ||
&& currentAcquisitionFile.PimsInterestHolders.Any(x => x.Internal_Id.Equals(compReq.InterestHolderId))) | ||
{ | ||
throw new ForeignKeyDependencyException("Acquisition File Interest Holders can not be removed since it's assigned as a payee for a compensation requisition"); | ||
} | ||
|
||
// Check for File Person | ||
if (compReq.AcquisitionFileTeamId is not null | ||
&& !acquisitionFile.PimsAcquisitionFileTeams.Any(x => x.Internal_Id.Equals(compReq.AcquisitionFileTeamId)) | ||
&& currentAquisitionFile.PimsAcquisitionFileTeams.Any(x => x.Internal_Id.Equals(compReq.AcquisitionFileTeamId))) | ||
&& currentAcquisitionFile.PimsAcquisitionFileTeams.Any(x => x.Internal_Id.Equals(compReq.AcquisitionFileTeamId))) | ||
{ | ||
throw new ForeignKeyDependencyException("Acquisition File team member can not be removed since it's assigned as a payee for a compensation requisition"); | ||
} | ||
|
@@ -876,7 +923,7 @@ | |
|
||
private void ValidateInterestHoldersDependency(long acquisitionFileId, List<PimsInterestHolder> interestHolders) | ||
{ | ||
var currentAquisitionFile = _acqFileRepository.GetById(acquisitionFileId); | ||
var currentAcquisitionFile = _acqFileRepository.GetById(acquisitionFileId); | ||
var compensationRequisitions = _compensationRequisitionRepository.GetAllByAcquisitionFileId(acquisitionFileId); | ||
|
||
if (compensationRequisitions.Count == 0) | ||
|
@@ -889,11 +936,24 @@ | |
// Check for Interest Holder | ||
if (compReq.InterestHolderId is not null | ||
&& !interestHolders.Any(x => x.InterestHolderId.Equals(compReq.InterestHolderId)) | ||
&& currentAquisitionFile.PimsInterestHolders.Any(x => x.Internal_Id.Equals(compReq.InterestHolderId))) | ||
&& currentAcquisitionFile.PimsInterestHolders.Any(x => x.Internal_Id.Equals(compReq.InterestHolderId))) | ||
{ | ||
throw new ForeignKeyDependencyException("Acquisition File Interest Holder can not be removed since it's assigned as a payee for a compensation requisition"); | ||
} | ||
} | ||
} | ||
|
||
private AcquisitionStatusTypes? GetCurrentAcquisitionStatus(long acquisitionFileId) | ||
{ | ||
var currentAcquisitionFile = _acqFileRepository.GetById(acquisitionFileId); | ||
AcquisitionStatusTypes currentAcquisitionStatus; | ||
|
||
if (Enum.TryParse(currentAcquisitionFile.AcquisitionFileStatusTypeCode, out currentAcquisitionStatus)) | ||
{ | ||
return currentAcquisitionStatus; | ||
} | ||
|
||
return currentAcquisitionStatus; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like you added an explicit check/throw for stakeholders and checklists even though those errors will not get thrown in current state. I'm fine with that as it provides a consistent pattern for update logic, but doesn't that mean you should add a check for updateProperties as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I gather on the confluence page the properties are allowed to be updated at all times (all statues)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right, but the same applies to stakeholders and checklists, why have explicit logic for those and not for properties?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I understand what you are saying now. Initially I had it like that, but it felt like adding those checks was adding unnecessary complexity. If you feel strongly about it I can add them back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm neutral about it.